This repository was archived by the owner on Aug 27, 2026. It is now read-only.

Remove $(AndroidGenerateJniMarshalMethods) support - #1405

Merged
jonathanpeppers merged 5 commits into
mainfrom
jonathanpeppers/dev-peppers-remove-jni-marshal-methods
Apr 27, 2026
Merged

Remove $(AndroidGenerateJniMarshalMethods) support#1405
jonathanpeppers merged 5 commits into
mainfrom
jonathanpeppers/dev-peppers-remove-jni-marshal-methods

Conversation

@jonathanpeppers

Copy link
Copy Markdown
Member

Context: dotnet/android@4296716

Summary

Remove the $(AndroidGenerateJniMarshalMethods) infrastructure from java-interop, which was already removed from dotnet/android.

44 files changed, 54 insertions, 5,513 deletions

What's removed

  • tools/jnimarshalmethod-gen/ — the marshal method generator tool
  • src/Java.Interop.Export/MarshalMemberBuilder implementation + [JavaCallable] attributes
  • tests/Java.Interop.Export-Tests/ — tests for the above
  • src/Java.Interop.Tools.Expressions/ — Expression-to-IL compiler used only by jnimarshalmethod-gen
  • tests/Java.Interop.Tools.Expressions-Tests/ — tests for the above

What's kept (marked [Obsolete])

All public APIs in Java.Interop.dll are retained but obsoleted:

  • CreationOptions.UseMarshalMemberBuilder
  • CreationOptions.MarshalMemberBuilder
  • JniRuntime.MarshalMemberBuilder
  • JniRuntime.JniMarshalMemberBuilder abstract class + all members

Non-abstract methods now throw NotSupportedException.

Runtime simplification

  • JreTypeManager.RegisterNativeMembers — removed the MarshalMemberBuilder fallback path; now throws if TryRegisterNativeMembers fails
  • ManagedValueManager.ActivatePeer — always uses reflection activation
  • MonoRuntimeValueManager.ActivatePeer — uses reflection activation instead of MarshalMemberBuilder.CreateConstructActivationPeerFunc

dotnet/android impact

dotnet/android sets UseMarshalMemberBuilder = false in two places. After this change, those lines should be removed (they'll generate [Obsolete] warnings):

  • src/Mono.Android/Android.Runtime/AndroidRuntime.cs
  • src/Microsoft.Android.Runtime.NativeAOT/Android.Runtime.NativeAOT/JavaInteropRuntime.cs

Build & test

  • Solution builds successfully
  • Java.Interop-Tests: 665 passed, 0 failed
  • JCW-Tests: 47 passed, 0 failed

Delete the jnimarshalmethod-gen tool, Java.Interop.Export library,
Java.Interop.Export-Tests, and Java.Interop.Tools.Expressions projects.
All public APIs in Java.Interop.dll (JniMarshalMemberBuilder,
CreationOptions.UseMarshalMemberBuilder, etc.) are retained but marked
[Obsolete] with no-op implementations.
Runtime code in JreTypeManager, ManagedValueManager, and
MonoRuntimeValueManager is simplified to remove MarshalMemberBuilder
fallback paths.
NativeAOT samples, Makefile, and CI pipeline are updated accordingly.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jonathanpeppers added a commit to dotnet/android that referenced this pull request Apr 16, 2026
Bump \�xternal/Java.Interop\ to dotnet/java-interop#1405, which removes
\Java.Interop.Export\, \jnimarshalmethod-gen\, and
\Java.Interop.Tools.Expressions\.
Changes in dotnet/android:
- Remove \UseMarshalMemberBuilder = false\ from AndroidRuntime and
NativeAOT JavaInteropRuntime (property is now obsolete/no-op).
- Remove deleted \Java.Interop.Export\ and
\Xamarin.Android.Tools.JniMarshalMethodGenerator\ projects from
\Xamarin.Android.sln\.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…eManager trim warnings
- JreTypeManager: Simplify RegisterNativeMembers to return early when
methods is empty (types like JavaProxyThrowable register with no
methods), and throw for non-empty methods without static registration.
- MonoRuntimeValueManager: Add trim suppression attributes for
GetUninitializedObject call to fix NativeAOT publish errors.
- Java.Base-Tests: Add explicit marshal methods and static registration
to MyRunnable and MyIntConsumer test types, since dynamic marshal
method generation via MarshalMemberBuilder is no longer available.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jonathanpeppers
jonathanpeppersforce-pushed the jonathanpeppers/dev-peppers-remove-jni-marshal-methods branch from 01256d8 to 5cb82cdCompareApril 17, 2026 13:51
jonathanpeppersand others added 3 commits April 17, 2026 11:58
…hal methods
ManagedType.cs used [JavaCallable] attributes which relied on the
now-removed jnimarshalmethod-gen tool. Replace with explicit n_*
marshal methods and [JniAddNativeMethodRegistration] static registration.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ration
jcw-gen uses Cecil to find [JavaCallable] and [JavaCallableConstructor]
by attribute name to emit Java-side methods. These attributes must still
exist at compile time for the JCW to include getString() and the
constructor.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
NativeAOT requires delegate types used for JNI callbacks to have
[UnmanagedFunctionPointer] for proper marshalling data generation.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jonathanpeppers added a commit to dotnet/android that referenced this pull request Apr 22, 2026
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jonathanpeppers added a commit to dotnet/android that referenced this pull request Apr 22, 2026
…et/java-interop#1405
- Remove UseMarshalMemberBuilder = false from AndroidRuntime and
NativeAOT JavaInteropRuntime (property is now obsolete/no-op).
- Remove deleted Java.Interop.Export and
Xamarin.Android.Tools.JniMarshalMethodGenerator projects from
Xamarin.Android.sln.
- Bump external/Java.Interop submodule to PR 1405 head.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jonathanpeppers

Copy link
Copy Markdown
MemberAuthor

The dotnet/android test PR looks OK:

There are some flaky tests, but everything builds.

@jonathanpeppers
jonathanpeppers marked this pull request as ready for review April 23, 2026 18:27
CopilotAI review requested due to automatic review settings April 23, 2026 18:27

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR removes the legacy $(AndroidGenerateJniMarshalMethods)-driven marshal-method generation infrastructure from java-interop, aligning with the earlier removal in dotnet/android, while keeping the public surface area in Java.Interop.dll as [Obsolete] stubs that now throw NotSupportedException.

Changes:

  • Removes the jnimarshalmethod-gen tool and the Java.Interop.Export / Java.Interop.Tools.Expressions projects (plus associated tests and pipeline hooks).
  • Simplifies runtime activation/registration paths to rely on reflection and explicit [JniAddNativeMethodRegistration] patterns instead of MarshalMemberBuilder.
  • Updates samples and tests to no longer depend on Java.Interop.Export and generated marshal methods.

Reviewed changes

Copilot reviewed 44 out of 46 changed files in this pull request and generated 2 comments.

Show a summary per file
FileDescription
tools/jnimarshalmethod-gen/Xamarin.Android.Tools.JniMarshalMethodGenerator.csprojDeletes the marshal-method generator tool project.
tools/jnimarshalmethod-gen/TypeMover.csRemoves type-moving logic used by the generator.
tools/jnimarshalmethod-gen/Message.csRemoves generator-specific localized messages.
tools/jnimarshalmethod-gen/App.csRemoves generator app entrypoint and processing pipeline.
tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop/JavaCallableConstructorAttribute.csAdds local test-only attribute type to replace removed Export assembly dependency.
tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop/JavaCallableAttribute.csAdds local test-only attribute type to replace removed Export assembly dependency.
tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop.Tools.JavaCallableWrappers-Tests.csprojStops compiling attribute sources from Java.Interop.Export.
tests/Java.Interop.Tools.Expressions-Tests/Usings.csRemoves global using as the Expressions test project is removed.
tests/Java.Interop.Tools.Expressions-Tests/Java.Interop.Tools.ExpressionsTests/ExpressionAssemblyBuilderTests.csDeletes tests for the removed Expressions toolchain.
tests/Java.Interop.Tools.Expressions-Tests/Java.Interop.Tools.Expressions-Tests.csprojDeletes the Expressions test project.
tests/Java.Interop.Export-Tests/java/net/dot/jni/test/UseJavaCallableExample.javaDeletes Export test Java sources.
tests/Java.Interop.Export-Tests/java/net/dot/jni/test/ExportType.javaDeletes Export test Java sources.
tests/Java.Interop.Export-Tests/Java.Interop/MarshalMemberBuilderTest.csDeletes Export/MarshalMemberBuilder test coverage.
tests/Java.Interop.Export-Tests/Java.Interop/JavaVMFixture.csDeletes fixture used only by Export tests.
tests/Java.Interop.Export-Tests/Java.Interop/JavaCallableExampleTests.csDeletes JavaCallable example tests tied to Export infra.
tests/Java.Interop.Export-Tests/Java.Interop/JavaCallableExample.csDeletes JavaCallable example type tied to Export infra.
tests/Java.Interop.Export-Tests/Java.Interop/ExportTest.csDeletes ExportTest type which relied on MarshalMemberBuilder.
tests/Java.Interop.Export-Tests/Java.Interop.Export-Tests.targetsDeletes MSBuild targets used to build Export test jar and wrappers.
tests/Java.Interop.Export-Tests/Java.Interop.Export-Tests.csprojDeletes Export tests project.
tests/Java.Interop-Tests/Java.Interop/TestType.csStops using MarshalMemberBuilder.CreateMarshalToManagedDelegate(); returns existing delegate directly.
tests/Java.Interop-Tests/Java.Interop/JniRuntimeTest.csRemoves ProxyMarshalMemberBuilder test shim as marshal builder is no longer supported.
tests/Java.Base-Tests/Java.Base/JavaToManagedTests.csAdds explicit native registration methods instead of relying on marshal builder infrastructure.
src/Java.Runtime.Environment/Java.Runtime.Environment.csprojRemoves project reference to Java.Interop.Export.
src/Java.Runtime.Environment/Java.Interop/MonoRuntimeValueManager.csSwitches activation to reflection-based creation instead of CreateConstructActivationPeerFunc().
src/Java.Runtime.Environment/Java.Interop/ManagedValueManager.csRemoves marshal-member-builder activation branch; always uses reflection path.
src/Java.Runtime.Environment/Java.Interop/JreTypeManager.csRemoves marshal-member-builder fallback; now throws if registration isn’t handled explicitly.
src/Java.Interop/Java.Interop/JniRuntime.csRemoves initialization/disposal of marshal member builder.
src/Java.Interop/Java.Interop/JniRuntime.JniMarshalMemberBuilder.csObsoletes marshal member builder APIs; replaces behavior with NotSupportedException.
src/Java.Interop/GlobalSuppressions.csDrops suppression for removed IsDirectMethod analyzer case.
src/Java.Interop.Tools.Expressions/Java.Interop.Tools.Expressions/ExpressionMethodRegistration.csDeletes Expressions helper type.
src/Java.Interop.Tools.Expressions/Java.Interop.Tools.Expressions/ExpressionAssemblyBuilder.csDeletes Expressions-to-IL compiler utility.
src/Java.Interop.Tools.Expressions/Java.Interop.Tools.Expressions/CecilCompilerExpressionVisitor.csDeletes Expressions-to-IL compiler visitor.
src/Java.Interop.Tools.Expressions/Java.Interop.Tools.Expressions.csprojDeletes Expressions project.
src/Java.Interop.Export/Java.Interop/MarshalMemberBuilder.csDeletes Export-side MarshalMemberBuilder implementation.
src/Java.Interop.Export/Java.Interop.Export.csprojDeletes Export assembly project.
samples/Hello-NativeAOTFromJNI/ManagedType.csAdds explicit native registration/marshal method stub instead of post-build generator.
samples/Hello-NativeAOTFromJNI/JavaInteropRuntime.csRemoves UseMarshalMemberBuilder=false usage.
samples/Hello-NativeAOTFromJNI/JavaCallableAttributes.csAdds local attribute definitions for the sample (no Export dependency).
samples/Hello-NativeAOTFromJNI/Hello-NativeAOTFromJNI.targetsRemoves post-build _AddMarshalMethods target.
samples/Hello-NativeAOTFromJNI/Hello-NativeAOTFromJNI.csprojRemoves references to Export + jnimarshalmethod-gen tool projects.
samples/Hello-NativeAOTFromAndroid/JavaInteropRuntime.csRemoves UseMarshalMemberBuilder=false usage.
samples/Hello-NativeAOTFromAndroid/Hello-NativeAOTFromAndroid.targetsRemoves _AddMarshalMethods target and dependency ordering.
samples/Hello-NativeAOTFromAndroid/Hello-NativeAOTFromAndroid.csprojRemoves references to Export + jnimarshalmethod-gen tool projects.
build-tools/automation/templates/core-tests.yamlRemoves CI steps that ran Export tests and marshal-method generator.
MakefileRemoves Export test target and jnimarshalmethod-gen test recipe.
Java.Interop.slnRemoves Export/Expressions/tool projects from the solution.

Comment threadsamples/Hello-NativeAOTFromJNI/ManagedType.cs
Comment threadJava.Interop.sln
@jonathanpeppersjonathanpeppers added the ready-to-review This PR is ready to review/merge, thanks! label Apr 24, 2026

@simonrozsivalsimonrozsival left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

@jonathanpeppers
jonathanpeppers merged commit dedb8f8 into mainApr 27, 2026
6 checks passed
@jonathanpeppers
jonathanpeppers deleted the jonathanpeppers/dev-peppers-remove-jni-marshal-methods branch April 27, 2026 17:20
jonathanpeppers added a commit to dotnet/android that referenced this pull request Apr 27, 2026
…et/java-interop#1405
- Remove UseMarshalMemberBuilder = false from AndroidRuntime and
NativeAOT JavaInteropRuntime (property is now obsolete/no-op).
- Remove deleted Java.Interop.Export and
Xamarin.Android.Tools.JniMarshalMethodGenerator projects from
Xamarin.Android.sln.
- Bump external/Java.Interop submodule to PR 1405 head.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jonathanpeppers added a commit to dotnet/android that referenced this pull request Apr 28, 2026
### Remove UseMarshalMemberBuilder and bump external/Java.Interop to dotnet/java-interop#1405
- Remove UseMarshalMemberBuilder = false from AndroidRuntime and
NativeAOT JavaInteropRuntime (property is now obsolete/no-op).
- Remove deleted Java.Interop.Export and
Xamarin.Android.Tools.JniMarshalMethodGenerator projects from
Xamarin.Android.sln.
- Bump external/Java.Interop submodule to PR 1405 head.
### Copy java-interop.jar to SDK output directory
Add a ProjectReference to Java.Interop.csproj (with
ReferenceOutputAssembly=false) from Xamarin.Android.Build.Tasks.csproj
so that `java-interop.jar` (a Content item in Java.Interop.csproj) gets
copied to the output directory. Previously this happened transitively
through Java.Interop.Export which is now deleted.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
simonrozsival added a commit to dotnet/android that referenced this pull request May 11, 2026
…emap
[JniAddNativeMethodRegistrationAttribute] is a legacy Java.Interop API whose
primary consumer — the jnimarshalmethod-gen build-time generator — was
removed in dotnet/java-interop#1405. The trimmable typemap deliberately does
not support this attribute.
When the scanner detects the attribute on any method, the generator emits
XA4251 telling the developer to either avoid it or switch off the trimmable
typemap (for example, by using the 'llvm-ir' type map implementation) and
report the scenario at https://github.com/dotnet/android/issues. The build
fails via TaskLoggingHelper.HasLoggedErrors.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jonathanpeppers added a commit to dotnet/android that referenced this pull request May 14, 2026
…ith XA4251 (#11274)
### Use trimmable Java proxy runtime sources
Add trimmable-specific java_runtime jars that replace Java.Interop's JavaProxyObject and JavaProxyThrowable sources only for the trimmable typemap path. Keep the existing runtime jars on Java.Interop's native-registration behavior and select the trimmable jars when _AndroidTypeMapImplementation is trimmable.
Re-enable the affected Java.Interop runtime tests and add focused coverage for JavaProxyObject marshaling/object methods under the trimmable typemap path.
### Use trimmable virtual-constructor fixtures
Enable the Java.Interop virtual-constructor tests in the trimmable typemap lane by swapping in Android-owned Java fixtures that use Runtime.registerNatives and generated n_* callbacks instead of ManagedPeer.
Teach the trimmable typemap scanner/model to emit native registrations for hand-written Java peers that opt into JniAddNativeMethodRegistrationAttribute.
### Address Java proxy review comments
Use repository Java formatting for trimmable proxy sources and strengthen the proxy hashCode test so it compares against Java identityHashCode instead of itself.
### Simplify trimmable runtime artifacts
Drop stale _net6 Java runtime artifact names and collapse the trimmable runtime jar/dex to a single shared artifact for CoreCLR and NativeAOT.
### Drop unrelated obsolete-jar cleanup from java-runtime.targets and TrimmableTypeMapBuildTests
This cleanup is not related to fixing InvokeVirtualFromConstructorTests
and belongs in a separate change.
### Refuse [JniAddNativeMethodRegistrationAttribute] in the trimmable typemap
[JniAddNativeMethodRegistrationAttribute] is a legacy Java.Interop API whose
primary consumer — the jnimarshalmethod-gen build-time generator — was
removed in dotnet/java-interop#1405. The trimmable typemap deliberately does
not support this attribute.
When the scanner detects the attribute on any method, the generator emits
XA4251 telling the developer to either avoid it or switch off the trimmable
typemap (for example, by using the 'llvm-ir' type map implementation) and
report the scenario at https://github.com/dotnet/android/issues. The build
fails via TaskLoggingHelper.HasLoggedErrors.
### Move XA4251 reporting into JavaPeerScanner
Address review feedback:
- Drop JavaPeerInfo.HasJniAddNativeMethodRegistrationAttribute. The scanner
now takes an optional ITrimmableTypeMapLogger and reports XA4251 directly
when it encounters the attribute, instead of propagating a bool the rest
of the pipeline doesn't otherwise need.
- Drop the orchestrator's post-scan loop; TrimmableTypeMapGenerator just
passes its logger into JavaPeerScanner.
- Reset external/Java.Interop and external/xamarin-android-tools to the
SHAs on main; this PR doesn't need either submodule moved.
### Restore tests/Mono.Android-Tests/Java.Interop-Tests/java-trimmable/net/dot/jni/test/GetThis.java
This file is unrelated to the XA4251 work; it was accidentally removed during
an earlier 'git rm -r java-trimmable' cleanup. It's still needed by
JavaObjectTest.DisposeAccessesThis under the trimmable typemap.
### Exclude InvokeVirtualFromConstructor fixtures for trimmable
The upstream Java.Interop test fixture CallVirtualFromConstructorDerived
uses [JniAddNativeMethodRegistrationAttribute]. Now that the trimmable
typemap refuses that attribute with XA4251, the offending sources need to
be excluded from the test assembly when building for the trimmable type
map; otherwise the build cannot reach the device tests at all.
Validated locally:
ANDROID_SERIAL=emulator-5554 MSBUILDDISABLENODEREUSE=1 \
./dotnet-local.sh build \
tests/Mono.Android-Tests/Mono.Android-Tests/Mono.Android.NET-Tests.csproj \
-t:RunTestApp -c Release \
-p:_AndroidTypeMapImplementation=trimmable \
-p:UseMonoRuntime=false -nr:false -m:1
TestResult-Mono.Android.NET_Tests-ReleaseCoreCLRTrimmable.xml: 888 total,
0 errors, 0 failures, 21 ignored.
### Detect [JniAddNativeMethodRegistrationAttribute] on non-peer types too
Code-review caught that the prior placement of the XA4251 check sat *after*
the scanner's per-type filtering, so a type carrying the attribute but no
[Register] (and not extending a Java peer) would slip past the diagnostic
and the build would silently succeed.
Hoist the check to immediately after the <Module> skip so it fires uniformly
for every non-<Module> type, regardless of whether the type would otherwise
have been added to the typemap. Add a NonPeerNativeRegistration fixture to
the scanner test to guard the regression.
### Skip per-method XA4251 walk when assembly doesn't reference the attribute
Address Copilot reviewer feedback on the per-type method-attribute walk.
AssemblyIndex.Build now does a cheap pass over the TypeReferences and
TypeDefinitions tables to set MayUseJniAddNativeMethodRegistrationAttribute,
and the scanner short-circuits the per-method walk in the overwhelmingly
common case where the assembly neither imports nor declares the attribute.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Jonathan Peppers <jonathan.peppers@microsoft.com>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators May 28, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

ready-to-reviewThis PR is ready to review/merge, thanks!

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@jonathanpeppers@simonrozsival
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content
This repository was archived by the owner on Aug 27, 2026. It is now read-only.

Remove $(AndroidGenerateJniMarshalMethods) support - #1405

Merged
jonathanpeppers merged 5 commits into
mainfrom
jonathanpeppers/dev-peppers-remove-jni-marshal-methods
Apr 27, 2026
Merged

Remove $(AndroidGenerateJniMarshalMethods) support#1405
jonathanpeppers merged 5 commits into
mainfrom
jonathanpeppers/dev-peppers-remove-jni-marshal-methods

Conversation

@jonathanpeppers

Copy link
Copy Markdown
Member

Context: dotnet/android@4296716

Summary

Remove the $(AndroidGenerateJniMarshalMethods) infrastructure from java-interop, which was already removed from dotnet/android.

44 files changed, 54 insertions, 5,513 deletions

What's removed

  • tools/jnimarshalmethod-gen/ — the marshal method generator tool
  • src/Java.Interop.Export/MarshalMemberBuilder implementation + [JavaCallable] attributes
  • tests/Java.Interop.Export-Tests/ — tests for the above
  • src/Java.Interop.Tools.Expressions/ — Expression-to-IL compiler used only by jnimarshalmethod-gen
  • tests/Java.Interop.Tools.Expressions-Tests/ — tests for the above

What's kept (marked [Obsolete])

All public APIs in Java.Interop.dll are retained but obsoleted:

  • CreationOptions.UseMarshalMemberBuilder
  • CreationOptions.MarshalMemberBuilder
  • JniRuntime.MarshalMemberBuilder
  • JniRuntime.JniMarshalMemberBuilder abstract class + all members

Non-abstract methods now throw NotSupportedException.

Runtime simplification

  • JreTypeManager.RegisterNativeMembers — removed the MarshalMemberBuilder fallback path; now throws if TryRegisterNativeMembers fails
  • ManagedValueManager.ActivatePeer — always uses reflection activation
  • MonoRuntimeValueManager.ActivatePeer — uses reflection activation instead of MarshalMemberBuilder.CreateConstructActivationPeerFunc

dotnet/android impact

dotnet/android sets UseMarshalMemberBuilder = false in two places. After this change, those lines should be removed (they'll generate [Obsolete] warnings):

  • src/Mono.Android/Android.Runtime/AndroidRuntime.cs
  • src/Microsoft.Android.Runtime.NativeAOT/Android.Runtime.NativeAOT/JavaInteropRuntime.cs

Build & test

  • Solution builds successfully
  • Java.Interop-Tests: 665 passed, 0 failed
  • JCW-Tests: 47 passed, 0 failed

Delete the jnimarshalmethod-gen tool, Java.Interop.Export library,
Java.Interop.Export-Tests, and Java.Interop.Tools.Expressions projects.
All public APIs in Java.Interop.dll (JniMarshalMemberBuilder,
CreationOptions.UseMarshalMemberBuilder, etc.) are retained but marked
[Obsolete] with no-op implementations.
Runtime code in JreTypeManager, ManagedValueManager, and
MonoRuntimeValueManager is simplified to remove MarshalMemberBuilder
fallback paths.
NativeAOT samples, Makefile, and CI pipeline are updated accordingly.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jonathanpeppers added a commit to dotnet/android that referenced this pull request Apr 16, 2026
Bump \�xternal/Java.Interop\ to dotnet/java-interop#1405, which removes
\Java.Interop.Export\, \jnimarshalmethod-gen\, and
\Java.Interop.Tools.Expressions\.
Changes in dotnet/android:
- Remove \UseMarshalMemberBuilder = false\ from AndroidRuntime and
NativeAOT JavaInteropRuntime (property is now obsolete/no-op).
- Remove deleted \Java.Interop.Export\ and
\Xamarin.Android.Tools.JniMarshalMethodGenerator\ projects from
\Xamarin.Android.sln\.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…eManager trim warnings
- JreTypeManager: Simplify RegisterNativeMembers to return early when
methods is empty (types like JavaProxyThrowable register with no
methods), and throw for non-empty methods without static registration.
- MonoRuntimeValueManager: Add trim suppression attributes for
GetUninitializedObject call to fix NativeAOT publish errors.
- Java.Base-Tests: Add explicit marshal methods and static registration
to MyRunnable and MyIntConsumer test types, since dynamic marshal
method generation via MarshalMemberBuilder is no longer available.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jonathanpeppers
jonathanpeppersforce-pushed the jonathanpeppers/dev-peppers-remove-jni-marshal-methods branch from 01256d8 to 5cb82cdCompareApril 17, 2026 13:51
jonathanpeppersand others added 3 commits April 17, 2026 11:58
…hal methods
ManagedType.cs used [JavaCallable] attributes which relied on the
now-removed jnimarshalmethod-gen tool. Replace with explicit n_*
marshal methods and [JniAddNativeMethodRegistration] static registration.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ration
jcw-gen uses Cecil to find [JavaCallable] and [JavaCallableConstructor]
by attribute name to emit Java-side methods. These attributes must still
exist at compile time for the JCW to include getString() and the
constructor.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
NativeAOT requires delegate types used for JNI callbacks to have
[UnmanagedFunctionPointer] for proper marshalling data generation.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jonathanpeppers added a commit to dotnet/android that referenced this pull request Apr 22, 2026
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jonathanpeppers added a commit to dotnet/android that referenced this pull request Apr 22, 2026
…et/java-interop#1405
- Remove UseMarshalMemberBuilder = false from AndroidRuntime and
NativeAOT JavaInteropRuntime (property is now obsolete/no-op).
- Remove deleted Java.Interop.Export and
Xamarin.Android.Tools.JniMarshalMethodGenerator projects from
Xamarin.Android.sln.
- Bump external/Java.Interop submodule to PR 1405 head.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jonathanpeppers

Copy link
Copy Markdown
MemberAuthor

The dotnet/android test PR looks OK:

There are some flaky tests, but everything builds.

@jonathanpeppers
jonathanpeppers marked this pull request as ready for review April 23, 2026 18:27
CopilotAI review requested due to automatic review settings April 23, 2026 18:27

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR removes the legacy $(AndroidGenerateJniMarshalMethods)-driven marshal-method generation infrastructure from java-interop, aligning with the earlier removal in dotnet/android, while keeping the public surface area in Java.Interop.dll as [Obsolete] stubs that now throw NotSupportedException.

Changes:

  • Removes the jnimarshalmethod-gen tool and the Java.Interop.Export / Java.Interop.Tools.Expressions projects (plus associated tests and pipeline hooks).
  • Simplifies runtime activation/registration paths to rely on reflection and explicit [JniAddNativeMethodRegistration] patterns instead of MarshalMemberBuilder.
  • Updates samples and tests to no longer depend on Java.Interop.Export and generated marshal methods.

Reviewed changes

Copilot reviewed 44 out of 46 changed files in this pull request and generated 2 comments.

Show a summary per file
FileDescription
tools/jnimarshalmethod-gen/Xamarin.Android.Tools.JniMarshalMethodGenerator.csprojDeletes the marshal-method generator tool project.
tools/jnimarshalmethod-gen/TypeMover.csRemoves type-moving logic used by the generator.
tools/jnimarshalmethod-gen/Message.csRemoves generator-specific localized messages.
tools/jnimarshalmethod-gen/App.csRemoves generator app entrypoint and processing pipeline.
tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop/JavaCallableConstructorAttribute.csAdds local test-only attribute type to replace removed Export assembly dependency.
tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop/JavaCallableAttribute.csAdds local test-only attribute type to replace removed Export assembly dependency.
tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop.Tools.JavaCallableWrappers-Tests.csprojStops compiling attribute sources from Java.Interop.Export.
tests/Java.Interop.Tools.Expressions-Tests/Usings.csRemoves global using as the Expressions test project is removed.
tests/Java.Interop.Tools.Expressions-Tests/Java.Interop.Tools.ExpressionsTests/ExpressionAssemblyBuilderTests.csDeletes tests for the removed Expressions toolchain.
tests/Java.Interop.Tools.Expressions-Tests/Java.Interop.Tools.Expressions-Tests.csprojDeletes the Expressions test project.
tests/Java.Interop.Export-Tests/java/net/dot/jni/test/UseJavaCallableExample.javaDeletes Export test Java sources.
tests/Java.Interop.Export-Tests/java/net/dot/jni/test/ExportType.javaDeletes Export test Java sources.
tests/Java.Interop.Export-Tests/Java.Interop/MarshalMemberBuilderTest.csDeletes Export/MarshalMemberBuilder test coverage.
tests/Java.Interop.Export-Tests/Java.Interop/JavaVMFixture.csDeletes fixture used only by Export tests.
tests/Java.Interop.Export-Tests/Java.Interop/JavaCallableExampleTests.csDeletes JavaCallable example tests tied to Export infra.
tests/Java.Interop.Export-Tests/Java.Interop/JavaCallableExample.csDeletes JavaCallable example type tied to Export infra.
tests/Java.Interop.Export-Tests/Java.Interop/ExportTest.csDeletes ExportTest type which relied on MarshalMemberBuilder.
tests/Java.Interop.Export-Tests/Java.Interop.Export-Tests.targetsDeletes MSBuild targets used to build Export test jar and wrappers.
tests/Java.Interop.Export-Tests/Java.Interop.Export-Tests.csprojDeletes Export tests project.
tests/Java.Interop-Tests/Java.Interop/TestType.csStops using MarshalMemberBuilder.CreateMarshalToManagedDelegate(); returns existing delegate directly.
tests/Java.Interop-Tests/Java.Interop/JniRuntimeTest.csRemoves ProxyMarshalMemberBuilder test shim as marshal builder is no longer supported.
tests/Java.Base-Tests/Java.Base/JavaToManagedTests.csAdds explicit native registration methods instead of relying on marshal builder infrastructure.
src/Java.Runtime.Environment/Java.Runtime.Environment.csprojRemoves project reference to Java.Interop.Export.
src/Java.Runtime.Environment/Java.Interop/MonoRuntimeValueManager.csSwitches activation to reflection-based creation instead of CreateConstructActivationPeerFunc().
src/Java.Runtime.Environment/Java.Interop/ManagedValueManager.csRemoves marshal-member-builder activation branch; always uses reflection path.
src/Java.Runtime.Environment/Java.Interop/JreTypeManager.csRemoves marshal-member-builder fallback; now throws if registration isn’t handled explicitly.
src/Java.Interop/Java.Interop/JniRuntime.csRemoves initialization/disposal of marshal member builder.
src/Java.Interop/Java.Interop/JniRuntime.JniMarshalMemberBuilder.csObsoletes marshal member builder APIs; replaces behavior with NotSupportedException.
src/Java.Interop/GlobalSuppressions.csDrops suppression for removed IsDirectMethod analyzer case.
src/Java.Interop.Tools.Expressions/Java.Interop.Tools.Expressions/ExpressionMethodRegistration.csDeletes Expressions helper type.
src/Java.Interop.Tools.Expressions/Java.Interop.Tools.Expressions/ExpressionAssemblyBuilder.csDeletes Expressions-to-IL compiler utility.
src/Java.Interop.Tools.Expressions/Java.Interop.Tools.Expressions/CecilCompilerExpressionVisitor.csDeletes Expressions-to-IL compiler visitor.
src/Java.Interop.Tools.Expressions/Java.Interop.Tools.Expressions.csprojDeletes Expressions project.
src/Java.Interop.Export/Java.Interop/MarshalMemberBuilder.csDeletes Export-side MarshalMemberBuilder implementation.
src/Java.Interop.Export/Java.Interop.Export.csprojDeletes Export assembly project.
samples/Hello-NativeAOTFromJNI/ManagedType.csAdds explicit native registration/marshal method stub instead of post-build generator.
samples/Hello-NativeAOTFromJNI/JavaInteropRuntime.csRemoves UseMarshalMemberBuilder=false usage.
samples/Hello-NativeAOTFromJNI/JavaCallableAttributes.csAdds local attribute definitions for the sample (no Export dependency).
samples/Hello-NativeAOTFromJNI/Hello-NativeAOTFromJNI.targetsRemoves post-build _AddMarshalMethods target.
samples/Hello-NativeAOTFromJNI/Hello-NativeAOTFromJNI.csprojRemoves references to Export + jnimarshalmethod-gen tool projects.
samples/Hello-NativeAOTFromAndroid/JavaInteropRuntime.csRemoves UseMarshalMemberBuilder=false usage.
samples/Hello-NativeAOTFromAndroid/Hello-NativeAOTFromAndroid.targetsRemoves _AddMarshalMethods target and dependency ordering.
samples/Hello-NativeAOTFromAndroid/Hello-NativeAOTFromAndroid.csprojRemoves references to Export + jnimarshalmethod-gen tool projects.
build-tools/automation/templates/core-tests.yamlRemoves CI steps that ran Export tests and marshal-method generator.
MakefileRemoves Export test target and jnimarshalmethod-gen test recipe.
Java.Interop.slnRemoves Export/Expressions/tool projects from the solution.

Comment threadsamples/Hello-NativeAOTFromJNI/ManagedType.cs
Comment threadJava.Interop.sln
@jonathanpeppersjonathanpeppers added the ready-to-review This PR is ready to review/merge, thanks! label Apr 24, 2026

@simonrozsivalsimonrozsival left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

@jonathanpeppers
jonathanpeppers merged commit dedb8f8 into mainApr 27, 2026
6 checks passed
@jonathanpeppers
jonathanpeppers deleted the jonathanpeppers/dev-peppers-remove-jni-marshal-methods branch April 27, 2026 17:20
jonathanpeppers added a commit to dotnet/android that referenced this pull request Apr 27, 2026
…et/java-interop#1405
- Remove UseMarshalMemberBuilder = false from AndroidRuntime and
NativeAOT JavaInteropRuntime (property is now obsolete/no-op).
- Remove deleted Java.Interop.Export and
Xamarin.Android.Tools.JniMarshalMethodGenerator projects from
Xamarin.Android.sln.
- Bump external/Java.Interop submodule to PR 1405 head.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jonathanpeppers added a commit to dotnet/android that referenced this pull request Apr 28, 2026
### Remove UseMarshalMemberBuilder and bump external/Java.Interop to dotnet/java-interop#1405
- Remove UseMarshalMemberBuilder = false from AndroidRuntime and
NativeAOT JavaInteropRuntime (property is now obsolete/no-op).
- Remove deleted Java.Interop.Export and
Xamarin.Android.Tools.JniMarshalMethodGenerator projects from
Xamarin.Android.sln.
- Bump external/Java.Interop submodule to PR 1405 head.
### Copy java-interop.jar to SDK output directory
Add a ProjectReference to Java.Interop.csproj (with
ReferenceOutputAssembly=false) from Xamarin.Android.Build.Tasks.csproj
so that `java-interop.jar` (a Content item in Java.Interop.csproj) gets
copied to the output directory. Previously this happened transitively
through Java.Interop.Export which is now deleted.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
simonrozsival added a commit to dotnet/android that referenced this pull request May 11, 2026
…emap
[JniAddNativeMethodRegistrationAttribute] is a legacy Java.Interop API whose
primary consumer — the jnimarshalmethod-gen build-time generator — was
removed in dotnet/java-interop#1405. The trimmable typemap deliberately does
not support this attribute.
When the scanner detects the attribute on any method, the generator emits
XA4251 telling the developer to either avoid it or switch off the trimmable
typemap (for example, by using the 'llvm-ir' type map implementation) and
report the scenario at https://github.com/dotnet/android/issues. The build
fails via TaskLoggingHelper.HasLoggedErrors.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jonathanpeppers added a commit to dotnet/android that referenced this pull request May 14, 2026
…ith XA4251 (#11274)
### Use trimmable Java proxy runtime sources
Add trimmable-specific java_runtime jars that replace Java.Interop's JavaProxyObject and JavaProxyThrowable sources only for the trimmable typemap path. Keep the existing runtime jars on Java.Interop's native-registration behavior and select the trimmable jars when _AndroidTypeMapImplementation is trimmable.
Re-enable the affected Java.Interop runtime tests and add focused coverage for JavaProxyObject marshaling/object methods under the trimmable typemap path.
### Use trimmable virtual-constructor fixtures
Enable the Java.Interop virtual-constructor tests in the trimmable typemap lane by swapping in Android-owned Java fixtures that use Runtime.registerNatives and generated n_* callbacks instead of ManagedPeer.
Teach the trimmable typemap scanner/model to emit native registrations for hand-written Java peers that opt into JniAddNativeMethodRegistrationAttribute.
### Address Java proxy review comments
Use repository Java formatting for trimmable proxy sources and strengthen the proxy hashCode test so it compares against Java identityHashCode instead of itself.
### Simplify trimmable runtime artifacts
Drop stale _net6 Java runtime artifact names and collapse the trimmable runtime jar/dex to a single shared artifact for CoreCLR and NativeAOT.
### Drop unrelated obsolete-jar cleanup from java-runtime.targets and TrimmableTypeMapBuildTests
This cleanup is not related to fixing InvokeVirtualFromConstructorTests
and belongs in a separate change.
### Refuse [JniAddNativeMethodRegistrationAttribute] in the trimmable typemap
[JniAddNativeMethodRegistrationAttribute] is a legacy Java.Interop API whose
primary consumer — the jnimarshalmethod-gen build-time generator — was
removed in dotnet/java-interop#1405. The trimmable typemap deliberately does
not support this attribute.
When the scanner detects the attribute on any method, the generator emits
XA4251 telling the developer to either avoid it or switch off the trimmable
typemap (for example, by using the 'llvm-ir' type map implementation) and
report the scenario at https://github.com/dotnet/android/issues. The build
fails via TaskLoggingHelper.HasLoggedErrors.
### Move XA4251 reporting into JavaPeerScanner
Address review feedback:
- Drop JavaPeerInfo.HasJniAddNativeMethodRegistrationAttribute. The scanner
now takes an optional ITrimmableTypeMapLogger and reports XA4251 directly
when it encounters the attribute, instead of propagating a bool the rest
of the pipeline doesn't otherwise need.
- Drop the orchestrator's post-scan loop; TrimmableTypeMapGenerator just
passes its logger into JavaPeerScanner.
- Reset external/Java.Interop and external/xamarin-android-tools to the
SHAs on main; this PR doesn't need either submodule moved.
### Restore tests/Mono.Android-Tests/Java.Interop-Tests/java-trimmable/net/dot/jni/test/GetThis.java
This file is unrelated to the XA4251 work; it was accidentally removed during
an earlier 'git rm -r java-trimmable' cleanup. It's still needed by
JavaObjectTest.DisposeAccessesThis under the trimmable typemap.
### Exclude InvokeVirtualFromConstructor fixtures for trimmable
The upstream Java.Interop test fixture CallVirtualFromConstructorDerived
uses [JniAddNativeMethodRegistrationAttribute]. Now that the trimmable
typemap refuses that attribute with XA4251, the offending sources need to
be excluded from the test assembly when building for the trimmable type
map; otherwise the build cannot reach the device tests at all.
Validated locally:
ANDROID_SERIAL=emulator-5554 MSBUILDDISABLENODEREUSE=1 \
./dotnet-local.sh build \
tests/Mono.Android-Tests/Mono.Android-Tests/Mono.Android.NET-Tests.csproj \
-t:RunTestApp -c Release \
-p:_AndroidTypeMapImplementation=trimmable \
-p:UseMonoRuntime=false -nr:false -m:1
TestResult-Mono.Android.NET_Tests-ReleaseCoreCLRTrimmable.xml: 888 total,
0 errors, 0 failures, 21 ignored.
### Detect [JniAddNativeMethodRegistrationAttribute] on non-peer types too
Code-review caught that the prior placement of the XA4251 check sat *after*
the scanner's per-type filtering, so a type carrying the attribute but no
[Register] (and not extending a Java peer) would slip past the diagnostic
and the build would silently succeed.
Hoist the check to immediately after the <Module> skip so it fires uniformly
for every non-<Module> type, regardless of whether the type would otherwise
have been added to the typemap. Add a NonPeerNativeRegistration fixture to
the scanner test to guard the regression.
### Skip per-method XA4251 walk when assembly doesn't reference the attribute
Address Copilot reviewer feedback on the per-type method-attribute walk.
AssemblyIndex.Build now does a cheap pass over the TypeReferences and
TypeDefinitions tables to set MayUseJniAddNativeMethodRegistrationAttribute,
and the scanner short-circuits the per-method walk in the overwhelmingly
common case where the assembly neither imports nor declares the attribute.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Jonathan Peppers <jonathan.peppers@microsoft.com>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators May 28, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

ready-to-reviewThis PR is ready to review/merge, thanks!

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@jonathanpeppers@simonrozsival
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
This repository was archived by the owner on Aug 27, 2026. It is now read-only.

Remove $(AndroidGenerateJniMarshalMethods) support - #1405

Merged
jonathanpeppers merged 5 commits into
mainfrom
jonathanpeppers/dev-peppers-remove-jni-marshal-methods
Apr 27, 2026
Merged

Remove $(AndroidGenerateJniMarshalMethods) support#1405
jonathanpeppers merged 5 commits into
mainfrom
jonathanpeppers/dev-peppers-remove-jni-marshal-methods

Conversation

@jonathanpeppers

Copy link
Copy Markdown
Member

Context: dotnet/android@4296716

Summary

Remove the $(AndroidGenerateJniMarshalMethods) infrastructure from java-interop, which was already removed from dotnet/android.

44 files changed, 54 insertions, 5,513 deletions

What's removed

  • tools/jnimarshalmethod-gen/ — the marshal method generator tool
  • src/Java.Interop.Export/MarshalMemberBuilder implementation + [JavaCallable] attributes
  • tests/Java.Interop.Export-Tests/ — tests for the above
  • src/Java.Interop.Tools.Expressions/ — Expression-to-IL compiler used only by jnimarshalmethod-gen
  • tests/Java.Interop.Tools.Expressions-Tests/ — tests for the above

What's kept (marked [Obsolete])

All public APIs in Java.Interop.dll are retained but obsoleted:

  • CreationOptions.UseMarshalMemberBuilder
  • CreationOptions.MarshalMemberBuilder
  • JniRuntime.MarshalMemberBuilder
  • JniRuntime.JniMarshalMemberBuilder abstract class + all members

Non-abstract methods now throw NotSupportedException.

Runtime simplification

  • JreTypeManager.RegisterNativeMembers — removed the MarshalMemberBuilder fallback path; now throws if TryRegisterNativeMembers fails
  • ManagedValueManager.ActivatePeer — always uses reflection activation
  • MonoRuntimeValueManager.ActivatePeer — uses reflection activation instead of MarshalMemberBuilder.CreateConstructActivationPeerFunc

dotnet/android impact

dotnet/android sets UseMarshalMemberBuilder = false in two places. After this change, those lines should be removed (they'll generate [Obsolete] warnings):

  • src/Mono.Android/Android.Runtime/AndroidRuntime.cs
  • src/Microsoft.Android.Runtime.NativeAOT/Android.Runtime.NativeAOT/JavaInteropRuntime.cs

Build & test

  • Solution builds successfully
  • Java.Interop-Tests: 665 passed, 0 failed
  • JCW-Tests: 47 passed, 0 failed

Delete the jnimarshalmethod-gen tool, Java.Interop.Export library,
Java.Interop.Export-Tests, and Java.Interop.Tools.Expressions projects.
All public APIs in Java.Interop.dll (JniMarshalMemberBuilder,
CreationOptions.UseMarshalMemberBuilder, etc.) are retained but marked
[Obsolete] with no-op implementations.
Runtime code in JreTypeManager, ManagedValueManager, and
MonoRuntimeValueManager is simplified to remove MarshalMemberBuilder
fallback paths.
NativeAOT samples, Makefile, and CI pipeline are updated accordingly.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jonathanpeppers added a commit to dotnet/android that referenced this pull request Apr 16, 2026
Bump \�xternal/Java.Interop\ to dotnet/java-interop#1405, which removes
\Java.Interop.Export\, \jnimarshalmethod-gen\, and
\Java.Interop.Tools.Expressions\.
Changes in dotnet/android:
- Remove \UseMarshalMemberBuilder = false\ from AndroidRuntime and
NativeAOT JavaInteropRuntime (property is now obsolete/no-op).
- Remove deleted \Java.Interop.Export\ and
\Xamarin.Android.Tools.JniMarshalMethodGenerator\ projects from
\Xamarin.Android.sln\.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…eManager trim warnings
- JreTypeManager: Simplify RegisterNativeMembers to return early when
methods is empty (types like JavaProxyThrowable register with no
methods), and throw for non-empty methods without static registration.
- MonoRuntimeValueManager: Add trim suppression attributes for
GetUninitializedObject call to fix NativeAOT publish errors.
- Java.Base-Tests: Add explicit marshal methods and static registration
to MyRunnable and MyIntConsumer test types, since dynamic marshal
method generation via MarshalMemberBuilder is no longer available.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jonathanpeppers
jonathanpeppersforce-pushed the jonathanpeppers/dev-peppers-remove-jni-marshal-methods branch from 01256d8 to 5cb82cdCompareApril 17, 2026 13:51
jonathanpeppersand others added 3 commits April 17, 2026 11:58
…hal methods
ManagedType.cs used [JavaCallable] attributes which relied on the
now-removed jnimarshalmethod-gen tool. Replace with explicit n_*
marshal methods and [JniAddNativeMethodRegistration] static registration.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ration
jcw-gen uses Cecil to find [JavaCallable] and [JavaCallableConstructor]
by attribute name to emit Java-side methods. These attributes must still
exist at compile time for the JCW to include getString() and the
constructor.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
NativeAOT requires delegate types used for JNI callbacks to have
[UnmanagedFunctionPointer] for proper marshalling data generation.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jonathanpeppers added a commit to dotnet/android that referenced this pull request Apr 22, 2026
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jonathanpeppers added a commit to dotnet/android that referenced this pull request Apr 22, 2026
…et/java-interop#1405
- Remove UseMarshalMemberBuilder = false from AndroidRuntime and
NativeAOT JavaInteropRuntime (property is now obsolete/no-op).
- Remove deleted Java.Interop.Export and
Xamarin.Android.Tools.JniMarshalMethodGenerator projects from
Xamarin.Android.sln.
- Bump external/Java.Interop submodule to PR 1405 head.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jonathanpeppers

Copy link
Copy Markdown
MemberAuthor

The dotnet/android test PR looks OK:

There are some flaky tests, but everything builds.

@jonathanpeppers
jonathanpeppers marked this pull request as ready for review April 23, 2026 18:27
CopilotAI review requested due to automatic review settings April 23, 2026 18:27

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR removes the legacy $(AndroidGenerateJniMarshalMethods)-driven marshal-method generation infrastructure from java-interop, aligning with the earlier removal in dotnet/android, while keeping the public surface area in Java.Interop.dll as [Obsolete] stubs that now throw NotSupportedException.

Changes:

  • Removes the jnimarshalmethod-gen tool and the Java.Interop.Export / Java.Interop.Tools.Expressions projects (plus associated tests and pipeline hooks).
  • Simplifies runtime activation/registration paths to rely on reflection and explicit [JniAddNativeMethodRegistration] patterns instead of MarshalMemberBuilder.
  • Updates samples and tests to no longer depend on Java.Interop.Export and generated marshal methods.

Reviewed changes

Copilot reviewed 44 out of 46 changed files in this pull request and generated 2 comments.

Show a summary per file
FileDescription
tools/jnimarshalmethod-gen/Xamarin.Android.Tools.JniMarshalMethodGenerator.csprojDeletes the marshal-method generator tool project.
tools/jnimarshalmethod-gen/TypeMover.csRemoves type-moving logic used by the generator.
tools/jnimarshalmethod-gen/Message.csRemoves generator-specific localized messages.
tools/jnimarshalmethod-gen/App.csRemoves generator app entrypoint and processing pipeline.
tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop/JavaCallableConstructorAttribute.csAdds local test-only attribute type to replace removed Export assembly dependency.
tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop/JavaCallableAttribute.csAdds local test-only attribute type to replace removed Export assembly dependency.
tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop.Tools.JavaCallableWrappers-Tests.csprojStops compiling attribute sources from Java.Interop.Export.
tests/Java.Interop.Tools.Expressions-Tests/Usings.csRemoves global using as the Expressions test project is removed.
tests/Java.Interop.Tools.Expressions-Tests/Java.Interop.Tools.ExpressionsTests/ExpressionAssemblyBuilderTests.csDeletes tests for the removed Expressions toolchain.
tests/Java.Interop.Tools.Expressions-Tests/Java.Interop.Tools.Expressions-Tests.csprojDeletes the Expressions test project.
tests/Java.Interop.Export-Tests/java/net/dot/jni/test/UseJavaCallableExample.javaDeletes Export test Java sources.
tests/Java.Interop.Export-Tests/java/net/dot/jni/test/ExportType.javaDeletes Export test Java sources.
tests/Java.Interop.Export-Tests/Java.Interop/MarshalMemberBuilderTest.csDeletes Export/MarshalMemberBuilder test coverage.
tests/Java.Interop.Export-Tests/Java.Interop/JavaVMFixture.csDeletes fixture used only by Export tests.
tests/Java.Interop.Export-Tests/Java.Interop/JavaCallableExampleTests.csDeletes JavaCallable example tests tied to Export infra.
tests/Java.Interop.Export-Tests/Java.Interop/JavaCallableExample.csDeletes JavaCallable example type tied to Export infra.
tests/Java.Interop.Export-Tests/Java.Interop/ExportTest.csDeletes ExportTest type which relied on MarshalMemberBuilder.
tests/Java.Interop.Export-Tests/Java.Interop.Export-Tests.targetsDeletes MSBuild targets used to build Export test jar and wrappers.
tests/Java.Interop.Export-Tests/Java.Interop.Export-Tests.csprojDeletes Export tests project.
tests/Java.Interop-Tests/Java.Interop/TestType.csStops using MarshalMemberBuilder.CreateMarshalToManagedDelegate(); returns existing delegate directly.
tests/Java.Interop-Tests/Java.Interop/JniRuntimeTest.csRemoves ProxyMarshalMemberBuilder test shim as marshal builder is no longer supported.
tests/Java.Base-Tests/Java.Base/JavaToManagedTests.csAdds explicit native registration methods instead of relying on marshal builder infrastructure.
src/Java.Runtime.Environment/Java.Runtime.Environment.csprojRemoves project reference to Java.Interop.Export.
src/Java.Runtime.Environment/Java.Interop/MonoRuntimeValueManager.csSwitches activation to reflection-based creation instead of CreateConstructActivationPeerFunc().
src/Java.Runtime.Environment/Java.Interop/ManagedValueManager.csRemoves marshal-member-builder activation branch; always uses reflection path.
src/Java.Runtime.Environment/Java.Interop/JreTypeManager.csRemoves marshal-member-builder fallback; now throws if registration isn’t handled explicitly.
src/Java.Interop/Java.Interop/JniRuntime.csRemoves initialization/disposal of marshal member builder.
src/Java.Interop/Java.Interop/JniRuntime.JniMarshalMemberBuilder.csObsoletes marshal member builder APIs; replaces behavior with NotSupportedException.
src/Java.Interop/GlobalSuppressions.csDrops suppression for removed IsDirectMethod analyzer case.
src/Java.Interop.Tools.Expressions/Java.Interop.Tools.Expressions/ExpressionMethodRegistration.csDeletes Expressions helper type.
src/Java.Interop.Tools.Expressions/Java.Interop.Tools.Expressions/ExpressionAssemblyBuilder.csDeletes Expressions-to-IL compiler utility.
src/Java.Interop.Tools.Expressions/Java.Interop.Tools.Expressions/CecilCompilerExpressionVisitor.csDeletes Expressions-to-IL compiler visitor.
src/Java.Interop.Tools.Expressions/Java.Interop.Tools.Expressions.csprojDeletes Expressions project.
src/Java.Interop.Export/Java.Interop/MarshalMemberBuilder.csDeletes Export-side MarshalMemberBuilder implementation.
src/Java.Interop.Export/Java.Interop.Export.csprojDeletes Export assembly project.
samples/Hello-NativeAOTFromJNI/ManagedType.csAdds explicit native registration/marshal method stub instead of post-build generator.
samples/Hello-NativeAOTFromJNI/JavaInteropRuntime.csRemoves UseMarshalMemberBuilder=false usage.
samples/Hello-NativeAOTFromJNI/JavaCallableAttributes.csAdds local attribute definitions for the sample (no Export dependency).
samples/Hello-NativeAOTFromJNI/Hello-NativeAOTFromJNI.targetsRemoves post-build _AddMarshalMethods target.
samples/Hello-NativeAOTFromJNI/Hello-NativeAOTFromJNI.csprojRemoves references to Export + jnimarshalmethod-gen tool projects.
samples/Hello-NativeAOTFromAndroid/JavaInteropRuntime.csRemoves UseMarshalMemberBuilder=false usage.
samples/Hello-NativeAOTFromAndroid/Hello-NativeAOTFromAndroid.targetsRemoves _AddMarshalMethods target and dependency ordering.
samples/Hello-NativeAOTFromAndroid/Hello-NativeAOTFromAndroid.csprojRemoves references to Export + jnimarshalmethod-gen tool projects.
build-tools/automation/templates/core-tests.yamlRemoves CI steps that ran Export tests and marshal-method generator.
MakefileRemoves Export test target and jnimarshalmethod-gen test recipe.
Java.Interop.slnRemoves Export/Expressions/tool projects from the solution.

Comment threadsamples/Hello-NativeAOTFromJNI/ManagedType.cs
Comment threadJava.Interop.sln
@jonathanpeppersjonathanpeppers added the ready-to-review This PR is ready to review/merge, thanks! label Apr 24, 2026

@simonrozsivalsimonrozsival left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

@jonathanpeppers
jonathanpeppers merged commit dedb8f8 into mainApr 27, 2026
6 checks passed
@jonathanpeppers
jonathanpeppers deleted the jonathanpeppers/dev-peppers-remove-jni-marshal-methods branch April 27, 2026 17:20
jonathanpeppers added a commit to dotnet/android that referenced this pull request Apr 27, 2026
…et/java-interop#1405
- Remove UseMarshalMemberBuilder = false from AndroidRuntime and
NativeAOT JavaInteropRuntime (property is now obsolete/no-op).
- Remove deleted Java.Interop.Export and
Xamarin.Android.Tools.JniMarshalMethodGenerator projects from
Xamarin.Android.sln.
- Bump external/Java.Interop submodule to PR 1405 head.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jonathanpeppers added a commit to dotnet/android that referenced this pull request Apr 28, 2026
### Remove UseMarshalMemberBuilder and bump external/Java.Interop to dotnet/java-interop#1405
- Remove UseMarshalMemberBuilder = false from AndroidRuntime and
NativeAOT JavaInteropRuntime (property is now obsolete/no-op).
- Remove deleted Java.Interop.Export and
Xamarin.Android.Tools.JniMarshalMethodGenerator projects from
Xamarin.Android.sln.
- Bump external/Java.Interop submodule to PR 1405 head.
### Copy java-interop.jar to SDK output directory
Add a ProjectReference to Java.Interop.csproj (with
ReferenceOutputAssembly=false) from Xamarin.Android.Build.Tasks.csproj
so that `java-interop.jar` (a Content item in Java.Interop.csproj) gets
copied to the output directory. Previously this happened transitively
through Java.Interop.Export which is now deleted.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
simonrozsival added a commit to dotnet/android that referenced this pull request May 11, 2026
…emap
[JniAddNativeMethodRegistrationAttribute] is a legacy Java.Interop API whose
primary consumer — the jnimarshalmethod-gen build-time generator — was
removed in dotnet/java-interop#1405. The trimmable typemap deliberately does
not support this attribute.
When the scanner detects the attribute on any method, the generator emits
XA4251 telling the developer to either avoid it or switch off the trimmable
typemap (for example, by using the 'llvm-ir' type map implementation) and
report the scenario at https://github.com/dotnet/android/issues. The build
fails via TaskLoggingHelper.HasLoggedErrors.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jonathanpeppers added a commit to dotnet/android that referenced this pull request May 14, 2026
…ith XA4251 (#11274)
### Use trimmable Java proxy runtime sources
Add trimmable-specific java_runtime jars that replace Java.Interop's JavaProxyObject and JavaProxyThrowable sources only for the trimmable typemap path. Keep the existing runtime jars on Java.Interop's native-registration behavior and select the trimmable jars when _AndroidTypeMapImplementation is trimmable.
Re-enable the affected Java.Interop runtime tests and add focused coverage for JavaProxyObject marshaling/object methods under the trimmable typemap path.
### Use trimmable virtual-constructor fixtures
Enable the Java.Interop virtual-constructor tests in the trimmable typemap lane by swapping in Android-owned Java fixtures that use Runtime.registerNatives and generated n_* callbacks instead of ManagedPeer.
Teach the trimmable typemap scanner/model to emit native registrations for hand-written Java peers that opt into JniAddNativeMethodRegistrationAttribute.
### Address Java proxy review comments
Use repository Java formatting for trimmable proxy sources and strengthen the proxy hashCode test so it compares against Java identityHashCode instead of itself.
### Simplify trimmable runtime artifacts
Drop stale _net6 Java runtime artifact names and collapse the trimmable runtime jar/dex to a single shared artifact for CoreCLR and NativeAOT.
### Drop unrelated obsolete-jar cleanup from java-runtime.targets and TrimmableTypeMapBuildTests
This cleanup is not related to fixing InvokeVirtualFromConstructorTests
and belongs in a separate change.
### Refuse [JniAddNativeMethodRegistrationAttribute] in the trimmable typemap
[JniAddNativeMethodRegistrationAttribute] is a legacy Java.Interop API whose
primary consumer — the jnimarshalmethod-gen build-time generator — was
removed in dotnet/java-interop#1405. The trimmable typemap deliberately does
not support this attribute.
When the scanner detects the attribute on any method, the generator emits
XA4251 telling the developer to either avoid it or switch off the trimmable
typemap (for example, by using the 'llvm-ir' type map implementation) and
report the scenario at https://github.com/dotnet/android/issues. The build
fails via TaskLoggingHelper.HasLoggedErrors.
### Move XA4251 reporting into JavaPeerScanner
Address review feedback:
- Drop JavaPeerInfo.HasJniAddNativeMethodRegistrationAttribute. The scanner
now takes an optional ITrimmableTypeMapLogger and reports XA4251 directly
when it encounters the attribute, instead of propagating a bool the rest
of the pipeline doesn't otherwise need.
- Drop the orchestrator's post-scan loop; TrimmableTypeMapGenerator just
passes its logger into JavaPeerScanner.
- Reset external/Java.Interop and external/xamarin-android-tools to the
SHAs on main; this PR doesn't need either submodule moved.
### Restore tests/Mono.Android-Tests/Java.Interop-Tests/java-trimmable/net/dot/jni/test/GetThis.java
This file is unrelated to the XA4251 work; it was accidentally removed during
an earlier 'git rm -r java-trimmable' cleanup. It's still needed by
JavaObjectTest.DisposeAccessesThis under the trimmable typemap.
### Exclude InvokeVirtualFromConstructor fixtures for trimmable
The upstream Java.Interop test fixture CallVirtualFromConstructorDerived
uses [JniAddNativeMethodRegistrationAttribute]. Now that the trimmable
typemap refuses that attribute with XA4251, the offending sources need to
be excluded from the test assembly when building for the trimmable type
map; otherwise the build cannot reach the device tests at all.
Validated locally:
ANDROID_SERIAL=emulator-5554 MSBUILDDISABLENODEREUSE=1 \
./dotnet-local.sh build \
tests/Mono.Android-Tests/Mono.Android-Tests/Mono.Android.NET-Tests.csproj \
-t:RunTestApp -c Release \
-p:_AndroidTypeMapImplementation=trimmable \
-p:UseMonoRuntime=false -nr:false -m:1
TestResult-Mono.Android.NET_Tests-ReleaseCoreCLRTrimmable.xml: 888 total,
0 errors, 0 failures, 21 ignored.
### Detect [JniAddNativeMethodRegistrationAttribute] on non-peer types too
Code-review caught that the prior placement of the XA4251 check sat *after*
the scanner's per-type filtering, so a type carrying the attribute but no
[Register] (and not extending a Java peer) would slip past the diagnostic
and the build would silently succeed.
Hoist the check to immediately after the <Module> skip so it fires uniformly
for every non-<Module> type, regardless of whether the type would otherwise
have been added to the typemap. Add a NonPeerNativeRegistration fixture to
the scanner test to guard the regression.
### Skip per-method XA4251 walk when assembly doesn't reference the attribute
Address Copilot reviewer feedback on the per-type method-attribute walk.
AssemblyIndex.Build now does a cheap pass over the TypeReferences and
TypeDefinitions tables to set MayUseJniAddNativeMethodRegistrationAttribute,
and the scanner short-circuits the per-method walk in the overwhelmingly
common case where the assembly neither imports nor declares the attribute.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Jonathan Peppers <jonathan.peppers@microsoft.com>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators May 28, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

ready-to-reviewThis PR is ready to review/merge, thanks!

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@jonathanpeppers@simonrozsival
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
This repository was archived by the owner on Aug 27, 2026. It is now read-only.

Remove $(AndroidGenerateJniMarshalMethods) support - #1405

Merged
jonathanpeppers merged 5 commits into
mainfrom
jonathanpeppers/dev-peppers-remove-jni-marshal-methods
Apr 27, 2026
Merged

Remove $(AndroidGenerateJniMarshalMethods) support#1405
jonathanpeppers merged 5 commits into
mainfrom
jonathanpeppers/dev-peppers-remove-jni-marshal-methods

Conversation

@jonathanpeppers

Copy link
Copy Markdown
Member

Context: dotnet/android@4296716

Summary

Remove the $(AndroidGenerateJniMarshalMethods) infrastructure from java-interop, which was already removed from dotnet/android.

44 files changed, 54 insertions, 5,513 deletions

What's removed

  • tools/jnimarshalmethod-gen/ — the marshal method generator tool
  • src/Java.Interop.Export/MarshalMemberBuilder implementation + [JavaCallable] attributes
  • tests/Java.Interop.Export-Tests/ — tests for the above
  • src/Java.Interop.Tools.Expressions/ — Expression-to-IL compiler used only by jnimarshalmethod-gen
  • tests/Java.Interop.Tools.Expressions-Tests/ — tests for the above

What's kept (marked [Obsolete])

All public APIs in Java.Interop.dll are retained but obsoleted:

  • CreationOptions.UseMarshalMemberBuilder
  • CreationOptions.MarshalMemberBuilder
  • JniRuntime.MarshalMemberBuilder
  • JniRuntime.JniMarshalMemberBuilder abstract class + all members

Non-abstract methods now throw NotSupportedException.

Runtime simplification

  • JreTypeManager.RegisterNativeMembers — removed the MarshalMemberBuilder fallback path; now throws if TryRegisterNativeMembers fails
  • ManagedValueManager.ActivatePeer — always uses reflection activation
  • MonoRuntimeValueManager.ActivatePeer — uses reflection activation instead of MarshalMemberBuilder.CreateConstructActivationPeerFunc

dotnet/android impact

dotnet/android sets UseMarshalMemberBuilder = false in two places. After this change, those lines should be removed (they'll generate [Obsolete] warnings):

  • src/Mono.Android/Android.Runtime/AndroidRuntime.cs
  • src/Microsoft.Android.Runtime.NativeAOT/Android.Runtime.NativeAOT/JavaInteropRuntime.cs

Build & test

  • Solution builds successfully
  • Java.Interop-Tests: 665 passed, 0 failed
  • JCW-Tests: 47 passed, 0 failed

Delete the jnimarshalmethod-gen tool, Java.Interop.Export library,
Java.Interop.Export-Tests, and Java.Interop.Tools.Expressions projects.
All public APIs in Java.Interop.dll (JniMarshalMemberBuilder,
CreationOptions.UseMarshalMemberBuilder, etc.) are retained but marked
[Obsolete] with no-op implementations.
Runtime code in JreTypeManager, ManagedValueManager, and
MonoRuntimeValueManager is simplified to remove MarshalMemberBuilder
fallback paths.
NativeAOT samples, Makefile, and CI pipeline are updated accordingly.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jonathanpeppers added a commit to dotnet/android that referenced this pull request Apr 16, 2026
Bump \�xternal/Java.Interop\ to dotnet/java-interop#1405, which removes
\Java.Interop.Export\, \jnimarshalmethod-gen\, and
\Java.Interop.Tools.Expressions\.
Changes in dotnet/android:
- Remove \UseMarshalMemberBuilder = false\ from AndroidRuntime and
NativeAOT JavaInteropRuntime (property is now obsolete/no-op).
- Remove deleted \Java.Interop.Export\ and
\Xamarin.Android.Tools.JniMarshalMethodGenerator\ projects from
\Xamarin.Android.sln\.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…eManager trim warnings
- JreTypeManager: Simplify RegisterNativeMembers to return early when
methods is empty (types like JavaProxyThrowable register with no
methods), and throw for non-empty methods without static registration.
- MonoRuntimeValueManager: Add trim suppression attributes for
GetUninitializedObject call to fix NativeAOT publish errors.
- Java.Base-Tests: Add explicit marshal methods and static registration
to MyRunnable and MyIntConsumer test types, since dynamic marshal
method generation via MarshalMemberBuilder is no longer available.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jonathanpeppers
jonathanpeppersforce-pushed the jonathanpeppers/dev-peppers-remove-jni-marshal-methods branch from 01256d8 to 5cb82cdCompareApril 17, 2026 13:51
jonathanpeppersand others added 3 commits April 17, 2026 11:58
…hal methods
ManagedType.cs used [JavaCallable] attributes which relied on the
now-removed jnimarshalmethod-gen tool. Replace with explicit n_*
marshal methods and [JniAddNativeMethodRegistration] static registration.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ration
jcw-gen uses Cecil to find [JavaCallable] and [JavaCallableConstructor]
by attribute name to emit Java-side methods. These attributes must still
exist at compile time for the JCW to include getString() and the
constructor.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
NativeAOT requires delegate types used for JNI callbacks to have
[UnmanagedFunctionPointer] for proper marshalling data generation.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jonathanpeppers added a commit to dotnet/android that referenced this pull request Apr 22, 2026
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jonathanpeppers added a commit to dotnet/android that referenced this pull request Apr 22, 2026
…et/java-interop#1405
- Remove UseMarshalMemberBuilder = false from AndroidRuntime and
NativeAOT JavaInteropRuntime (property is now obsolete/no-op).
- Remove deleted Java.Interop.Export and
Xamarin.Android.Tools.JniMarshalMethodGenerator projects from
Xamarin.Android.sln.
- Bump external/Java.Interop submodule to PR 1405 head.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jonathanpeppers

Copy link
Copy Markdown
MemberAuthor

The dotnet/android test PR looks OK:

There are some flaky tests, but everything builds.

@jonathanpeppers
jonathanpeppers marked this pull request as ready for review April 23, 2026 18:27
CopilotAI review requested due to automatic review settings April 23, 2026 18:27

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR removes the legacy $(AndroidGenerateJniMarshalMethods)-driven marshal-method generation infrastructure from java-interop, aligning with the earlier removal in dotnet/android, while keeping the public surface area in Java.Interop.dll as [Obsolete] stubs that now throw NotSupportedException.

Changes:

  • Removes the jnimarshalmethod-gen tool and the Java.Interop.Export / Java.Interop.Tools.Expressions projects (plus associated tests and pipeline hooks).
  • Simplifies runtime activation/registration paths to rely on reflection and explicit [JniAddNativeMethodRegistration] patterns instead of MarshalMemberBuilder.
  • Updates samples and tests to no longer depend on Java.Interop.Export and generated marshal methods.

Reviewed changes

Copilot reviewed 44 out of 46 changed files in this pull request and generated 2 comments.

Show a summary per file
FileDescription
tools/jnimarshalmethod-gen/Xamarin.Android.Tools.JniMarshalMethodGenerator.csprojDeletes the marshal-method generator tool project.
tools/jnimarshalmethod-gen/TypeMover.csRemoves type-moving logic used by the generator.
tools/jnimarshalmethod-gen/Message.csRemoves generator-specific localized messages.
tools/jnimarshalmethod-gen/App.csRemoves generator app entrypoint and processing pipeline.
tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop/JavaCallableConstructorAttribute.csAdds local test-only attribute type to replace removed Export assembly dependency.
tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop/JavaCallableAttribute.csAdds local test-only attribute type to replace removed Export assembly dependency.
tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop.Tools.JavaCallableWrappers-Tests.csprojStops compiling attribute sources from Java.Interop.Export.
tests/Java.Interop.Tools.Expressions-Tests/Usings.csRemoves global using as the Expressions test project is removed.
tests/Java.Interop.Tools.Expressions-Tests/Java.Interop.Tools.ExpressionsTests/ExpressionAssemblyBuilderTests.csDeletes tests for the removed Expressions toolchain.
tests/Java.Interop.Tools.Expressions-Tests/Java.Interop.Tools.Expressions-Tests.csprojDeletes the Expressions test project.
tests/Java.Interop.Export-Tests/java/net/dot/jni/test/UseJavaCallableExample.javaDeletes Export test Java sources.
tests/Java.Interop.Export-Tests/java/net/dot/jni/test/ExportType.javaDeletes Export test Java sources.
tests/Java.Interop.Export-Tests/Java.Interop/MarshalMemberBuilderTest.csDeletes Export/MarshalMemberBuilder test coverage.
tests/Java.Interop.Export-Tests/Java.Interop/JavaVMFixture.csDeletes fixture used only by Export tests.
tests/Java.Interop.Export-Tests/Java.Interop/JavaCallableExampleTests.csDeletes JavaCallable example tests tied to Export infra.
tests/Java.Interop.Export-Tests/Java.Interop/JavaCallableExample.csDeletes JavaCallable example type tied to Export infra.
tests/Java.Interop.Export-Tests/Java.Interop/ExportTest.csDeletes ExportTest type which relied on MarshalMemberBuilder.
tests/Java.Interop.Export-Tests/Java.Interop.Export-Tests.targetsDeletes MSBuild targets used to build Export test jar and wrappers.
tests/Java.Interop.Export-Tests/Java.Interop.Export-Tests.csprojDeletes Export tests project.
tests/Java.Interop-Tests/Java.Interop/TestType.csStops using MarshalMemberBuilder.CreateMarshalToManagedDelegate(); returns existing delegate directly.
tests/Java.Interop-Tests/Java.Interop/JniRuntimeTest.csRemoves ProxyMarshalMemberBuilder test shim as marshal builder is no longer supported.
tests/Java.Base-Tests/Java.Base/JavaToManagedTests.csAdds explicit native registration methods instead of relying on marshal builder infrastructure.
src/Java.Runtime.Environment/Java.Runtime.Environment.csprojRemoves project reference to Java.Interop.Export.
src/Java.Runtime.Environment/Java.Interop/MonoRuntimeValueManager.csSwitches activation to reflection-based creation instead of CreateConstructActivationPeerFunc().
src/Java.Runtime.Environment/Java.Interop/ManagedValueManager.csRemoves marshal-member-builder activation branch; always uses reflection path.
src/Java.Runtime.Environment/Java.Interop/JreTypeManager.csRemoves marshal-member-builder fallback; now throws if registration isn’t handled explicitly.
src/Java.Interop/Java.Interop/JniRuntime.csRemoves initialization/disposal of marshal member builder.
src/Java.Interop/Java.Interop/JniRuntime.JniMarshalMemberBuilder.csObsoletes marshal member builder APIs; replaces behavior with NotSupportedException.
src/Java.Interop/GlobalSuppressions.csDrops suppression for removed IsDirectMethod analyzer case.
src/Java.Interop.Tools.Expressions/Java.Interop.Tools.Expressions/ExpressionMethodRegistration.csDeletes Expressions helper type.
src/Java.Interop.Tools.Expressions/Java.Interop.Tools.Expressions/ExpressionAssemblyBuilder.csDeletes Expressions-to-IL compiler utility.
src/Java.Interop.Tools.Expressions/Java.Interop.Tools.Expressions/CecilCompilerExpressionVisitor.csDeletes Expressions-to-IL compiler visitor.
src/Java.Interop.Tools.Expressions/Java.Interop.Tools.Expressions.csprojDeletes Expressions project.
src/Java.Interop.Export/Java.Interop/MarshalMemberBuilder.csDeletes Export-side MarshalMemberBuilder implementation.
src/Java.Interop.Export/Java.Interop.Export.csprojDeletes Export assembly project.
samples/Hello-NativeAOTFromJNI/ManagedType.csAdds explicit native registration/marshal method stub instead of post-build generator.
samples/Hello-NativeAOTFromJNI/JavaInteropRuntime.csRemoves UseMarshalMemberBuilder=false usage.
samples/Hello-NativeAOTFromJNI/JavaCallableAttributes.csAdds local attribute definitions for the sample (no Export dependency).
samples/Hello-NativeAOTFromJNI/Hello-NativeAOTFromJNI.targetsRemoves post-build _AddMarshalMethods target.
samples/Hello-NativeAOTFromJNI/Hello-NativeAOTFromJNI.csprojRemoves references to Export + jnimarshalmethod-gen tool projects.
samples/Hello-NativeAOTFromAndroid/JavaInteropRuntime.csRemoves UseMarshalMemberBuilder=false usage.
samples/Hello-NativeAOTFromAndroid/Hello-NativeAOTFromAndroid.targetsRemoves _AddMarshalMethods target and dependency ordering.
samples/Hello-NativeAOTFromAndroid/Hello-NativeAOTFromAndroid.csprojRemoves references to Export + jnimarshalmethod-gen tool projects.
build-tools/automation/templates/core-tests.yamlRemoves CI steps that ran Export tests and marshal-method generator.
MakefileRemoves Export test target and jnimarshalmethod-gen test recipe.
Java.Interop.slnRemoves Export/Expressions/tool projects from the solution.

Comment threadsamples/Hello-NativeAOTFromJNI/ManagedType.cs
Comment threadJava.Interop.sln
@jonathanpeppersjonathanpeppers added the ready-to-review This PR is ready to review/merge, thanks! label Apr 24, 2026

@simonrozsivalsimonrozsival left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

@jonathanpeppers
jonathanpeppers merged commit dedb8f8 into mainApr 27, 2026
6 checks passed
@jonathanpeppers
jonathanpeppers deleted the jonathanpeppers/dev-peppers-remove-jni-marshal-methods branch April 27, 2026 17:20
jonathanpeppers added a commit to dotnet/android that referenced this pull request Apr 27, 2026
…et/java-interop#1405
- Remove UseMarshalMemberBuilder = false from AndroidRuntime and
NativeAOT JavaInteropRuntime (property is now obsolete/no-op).
- Remove deleted Java.Interop.Export and
Xamarin.Android.Tools.JniMarshalMethodGenerator projects from
Xamarin.Android.sln.
- Bump external/Java.Interop submodule to PR 1405 head.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jonathanpeppers added a commit to dotnet/android that referenced this pull request Apr 28, 2026
### Remove UseMarshalMemberBuilder and bump external/Java.Interop to dotnet/java-interop#1405
- Remove UseMarshalMemberBuilder = false from AndroidRuntime and
NativeAOT JavaInteropRuntime (property is now obsolete/no-op).
- Remove deleted Java.Interop.Export and
Xamarin.Android.Tools.JniMarshalMethodGenerator projects from
Xamarin.Android.sln.
- Bump external/Java.Interop submodule to PR 1405 head.
### Copy java-interop.jar to SDK output directory
Add a ProjectReference to Java.Interop.csproj (with
ReferenceOutputAssembly=false) from Xamarin.Android.Build.Tasks.csproj
so that `java-interop.jar` (a Content item in Java.Interop.csproj) gets
copied to the output directory. Previously this happened transitively
through Java.Interop.Export which is now deleted.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
simonrozsival added a commit to dotnet/android that referenced this pull request May 11, 2026
…emap
[JniAddNativeMethodRegistrationAttribute] is a legacy Java.Interop API whose
primary consumer — the jnimarshalmethod-gen build-time generator — was
removed in dotnet/java-interop#1405. The trimmable typemap deliberately does
not support this attribute.
When the scanner detects the attribute on any method, the generator emits
XA4251 telling the developer to either avoid it or switch off the trimmable
typemap (for example, by using the 'llvm-ir' type map implementation) and
report the scenario at https://github.com/dotnet/android/issues. The build
fails via TaskLoggingHelper.HasLoggedErrors.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jonathanpeppers added a commit to dotnet/android that referenced this pull request May 14, 2026
…ith XA4251 (#11274)
### Use trimmable Java proxy runtime sources
Add trimmable-specific java_runtime jars that replace Java.Interop's JavaProxyObject and JavaProxyThrowable sources only for the trimmable typemap path. Keep the existing runtime jars on Java.Interop's native-registration behavior and select the trimmable jars when _AndroidTypeMapImplementation is trimmable.
Re-enable the affected Java.Interop runtime tests and add focused coverage for JavaProxyObject marshaling/object methods under the trimmable typemap path.
### Use trimmable virtual-constructor fixtures
Enable the Java.Interop virtual-constructor tests in the trimmable typemap lane by swapping in Android-owned Java fixtures that use Runtime.registerNatives and generated n_* callbacks instead of ManagedPeer.
Teach the trimmable typemap scanner/model to emit native registrations for hand-written Java peers that opt into JniAddNativeMethodRegistrationAttribute.
### Address Java proxy review comments
Use repository Java formatting for trimmable proxy sources and strengthen the proxy hashCode test so it compares against Java identityHashCode instead of itself.
### Simplify trimmable runtime artifacts
Drop stale _net6 Java runtime artifact names and collapse the trimmable runtime jar/dex to a single shared artifact for CoreCLR and NativeAOT.
### Drop unrelated obsolete-jar cleanup from java-runtime.targets and TrimmableTypeMapBuildTests
This cleanup is not related to fixing InvokeVirtualFromConstructorTests
and belongs in a separate change.
### Refuse [JniAddNativeMethodRegistrationAttribute] in the trimmable typemap
[JniAddNativeMethodRegistrationAttribute] is a legacy Java.Interop API whose
primary consumer — the jnimarshalmethod-gen build-time generator — was
removed in dotnet/java-interop#1405. The trimmable typemap deliberately does
not support this attribute.
When the scanner detects the attribute on any method, the generator emits
XA4251 telling the developer to either avoid it or switch off the trimmable
typemap (for example, by using the 'llvm-ir' type map implementation) and
report the scenario at https://github.com/dotnet/android/issues. The build
fails via TaskLoggingHelper.HasLoggedErrors.
### Move XA4251 reporting into JavaPeerScanner
Address review feedback:
- Drop JavaPeerInfo.HasJniAddNativeMethodRegistrationAttribute. The scanner
now takes an optional ITrimmableTypeMapLogger and reports XA4251 directly
when it encounters the attribute, instead of propagating a bool the rest
of the pipeline doesn't otherwise need.
- Drop the orchestrator's post-scan loop; TrimmableTypeMapGenerator just
passes its logger into JavaPeerScanner.
- Reset external/Java.Interop and external/xamarin-android-tools to the
SHAs on main; this PR doesn't need either submodule moved.
### Restore tests/Mono.Android-Tests/Java.Interop-Tests/java-trimmable/net/dot/jni/test/GetThis.java
This file is unrelated to the XA4251 work; it was accidentally removed during
an earlier 'git rm -r java-trimmable' cleanup. It's still needed by
JavaObjectTest.DisposeAccessesThis under the trimmable typemap.
### Exclude InvokeVirtualFromConstructor fixtures for trimmable
The upstream Java.Interop test fixture CallVirtualFromConstructorDerived
uses [JniAddNativeMethodRegistrationAttribute]. Now that the trimmable
typemap refuses that attribute with XA4251, the offending sources need to
be excluded from the test assembly when building for the trimmable type
map; otherwise the build cannot reach the device tests at all.
Validated locally:
ANDROID_SERIAL=emulator-5554 MSBUILDDISABLENODEREUSE=1 \
./dotnet-local.sh build \
tests/Mono.Android-Tests/Mono.Android-Tests/Mono.Android.NET-Tests.csproj \
-t:RunTestApp -c Release \
-p:_AndroidTypeMapImplementation=trimmable \
-p:UseMonoRuntime=false -nr:false -m:1
TestResult-Mono.Android.NET_Tests-ReleaseCoreCLRTrimmable.xml: 888 total,
0 errors, 0 failures, 21 ignored.
### Detect [JniAddNativeMethodRegistrationAttribute] on non-peer types too
Code-review caught that the prior placement of the XA4251 check sat *after*
the scanner's per-type filtering, so a type carrying the attribute but no
[Register] (and not extending a Java peer) would slip past the diagnostic
and the build would silently succeed.
Hoist the check to immediately after the <Module> skip so it fires uniformly
for every non-<Module> type, regardless of whether the type would otherwise
have been added to the typemap. Add a NonPeerNativeRegistration fixture to
the scanner test to guard the regression.
### Skip per-method XA4251 walk when assembly doesn't reference the attribute
Address Copilot reviewer feedback on the per-type method-attribute walk.
AssemblyIndex.Build now does a cheap pass over the TypeReferences and
TypeDefinitions tables to set MayUseJniAddNativeMethodRegistrationAttribute,
and the scanner short-circuits the per-method walk in the overwhelmingly
common case where the assembly neither imports nor declares the attribute.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Jonathan Peppers <jonathan.peppers@microsoft.com>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators May 28, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

ready-to-reviewThis PR is ready to review/merge, thanks!

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@jonathanpeppers@simonrozsival
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
This repository was archived by the owner on Aug 27, 2026. It is now read-only.

Remove $(AndroidGenerateJniMarshalMethods) support - #1405

Merged
jonathanpeppers merged 5 commits into
mainfrom
jonathanpeppers/dev-peppers-remove-jni-marshal-methods
Apr 27, 2026
Merged

Remove $(AndroidGenerateJniMarshalMethods) support#1405
jonathanpeppers merged 5 commits into
mainfrom
jonathanpeppers/dev-peppers-remove-jni-marshal-methods

Conversation

@jonathanpeppers

Copy link
Copy Markdown
Member

Context: dotnet/android@4296716

Summary

Remove the $(AndroidGenerateJniMarshalMethods) infrastructure from java-interop, which was already removed from dotnet/android.

44 files changed, 54 insertions, 5,513 deletions

What's removed

  • tools/jnimarshalmethod-gen/ — the marshal method generator tool
  • src/Java.Interop.Export/MarshalMemberBuilder implementation + [JavaCallable] attributes
  • tests/Java.Interop.Export-Tests/ — tests for the above
  • src/Java.Interop.Tools.Expressions/ — Expression-to-IL compiler used only by jnimarshalmethod-gen
  • tests/Java.Interop.Tools.Expressions-Tests/ — tests for the above

What's kept (marked [Obsolete])

All public APIs in Java.Interop.dll are retained but obsoleted:

  • CreationOptions.UseMarshalMemberBuilder
  • CreationOptions.MarshalMemberBuilder
  • JniRuntime.MarshalMemberBuilder
  • JniRuntime.JniMarshalMemberBuilder abstract class + all members

Non-abstract methods now throw NotSupportedException.

Runtime simplification

  • JreTypeManager.RegisterNativeMembers — removed the MarshalMemberBuilder fallback path; now throws if TryRegisterNativeMembers fails
  • ManagedValueManager.ActivatePeer — always uses reflection activation
  • MonoRuntimeValueManager.ActivatePeer — uses reflection activation instead of MarshalMemberBuilder.CreateConstructActivationPeerFunc

dotnet/android impact

dotnet/android sets UseMarshalMemberBuilder = false in two places. After this change, those lines should be removed (they'll generate [Obsolete] warnings):

  • src/Mono.Android/Android.Runtime/AndroidRuntime.cs
  • src/Microsoft.Android.Runtime.NativeAOT/Android.Runtime.NativeAOT/JavaInteropRuntime.cs

Build & test

  • Solution builds successfully
  • Java.Interop-Tests: 665 passed, 0 failed
  • JCW-Tests: 47 passed, 0 failed

Delete the jnimarshalmethod-gen tool, Java.Interop.Export library,
Java.Interop.Export-Tests, and Java.Interop.Tools.Expressions projects.
All public APIs in Java.Interop.dll (JniMarshalMemberBuilder,
CreationOptions.UseMarshalMemberBuilder, etc.) are retained but marked
[Obsolete] with no-op implementations.
Runtime code in JreTypeManager, ManagedValueManager, and
MonoRuntimeValueManager is simplified to remove MarshalMemberBuilder
fallback paths.
NativeAOT samples, Makefile, and CI pipeline are updated accordingly.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jonathanpeppers added a commit to dotnet/android that referenced this pull request Apr 16, 2026
Bump \�xternal/Java.Interop\ to dotnet/java-interop#1405, which removes
\Java.Interop.Export\, \jnimarshalmethod-gen\, and
\Java.Interop.Tools.Expressions\.
Changes in dotnet/android:
- Remove \UseMarshalMemberBuilder = false\ from AndroidRuntime and
NativeAOT JavaInteropRuntime (property is now obsolete/no-op).
- Remove deleted \Java.Interop.Export\ and
\Xamarin.Android.Tools.JniMarshalMethodGenerator\ projects from
\Xamarin.Android.sln\.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…eManager trim warnings
- JreTypeManager: Simplify RegisterNativeMembers to return early when
methods is empty (types like JavaProxyThrowable register with no
methods), and throw for non-empty methods without static registration.
- MonoRuntimeValueManager: Add trim suppression attributes for
GetUninitializedObject call to fix NativeAOT publish errors.
- Java.Base-Tests: Add explicit marshal methods and static registration
to MyRunnable and MyIntConsumer test types, since dynamic marshal
method generation via MarshalMemberBuilder is no longer available.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jonathanpeppers
jonathanpeppersforce-pushed the jonathanpeppers/dev-peppers-remove-jni-marshal-methods branch from 01256d8 to 5cb82cdCompareApril 17, 2026 13:51
jonathanpeppersand others added 3 commits April 17, 2026 11:58
…hal methods
ManagedType.cs used [JavaCallable] attributes which relied on the
now-removed jnimarshalmethod-gen tool. Replace with explicit n_*
marshal methods and [JniAddNativeMethodRegistration] static registration.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ration
jcw-gen uses Cecil to find [JavaCallable] and [JavaCallableConstructor]
by attribute name to emit Java-side methods. These attributes must still
exist at compile time for the JCW to include getString() and the
constructor.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
NativeAOT requires delegate types used for JNI callbacks to have
[UnmanagedFunctionPointer] for proper marshalling data generation.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jonathanpeppers added a commit to dotnet/android that referenced this pull request Apr 22, 2026
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jonathanpeppers added a commit to dotnet/android that referenced this pull request Apr 22, 2026
…et/java-interop#1405
- Remove UseMarshalMemberBuilder = false from AndroidRuntime and
NativeAOT JavaInteropRuntime (property is now obsolete/no-op).
- Remove deleted Java.Interop.Export and
Xamarin.Android.Tools.JniMarshalMethodGenerator projects from
Xamarin.Android.sln.
- Bump external/Java.Interop submodule to PR 1405 head.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jonathanpeppers

Copy link
Copy Markdown
MemberAuthor

The dotnet/android test PR looks OK:

There are some flaky tests, but everything builds.

@jonathanpeppers
jonathanpeppers marked this pull request as ready for review April 23, 2026 18:27
CopilotAI review requested due to automatic review settings April 23, 2026 18:27

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR removes the legacy $(AndroidGenerateJniMarshalMethods)-driven marshal-method generation infrastructure from java-interop, aligning with the earlier removal in dotnet/android, while keeping the public surface area in Java.Interop.dll as [Obsolete] stubs that now throw NotSupportedException.

Changes:

  • Removes the jnimarshalmethod-gen tool and the Java.Interop.Export / Java.Interop.Tools.Expressions projects (plus associated tests and pipeline hooks).
  • Simplifies runtime activation/registration paths to rely on reflection and explicit [JniAddNativeMethodRegistration] patterns instead of MarshalMemberBuilder.
  • Updates samples and tests to no longer depend on Java.Interop.Export and generated marshal methods.

Reviewed changes

Copilot reviewed 44 out of 46 changed files in this pull request and generated 2 comments.

Show a summary per file
FileDescription
tools/jnimarshalmethod-gen/Xamarin.Android.Tools.JniMarshalMethodGenerator.csprojDeletes the marshal-method generator tool project.
tools/jnimarshalmethod-gen/TypeMover.csRemoves type-moving logic used by the generator.
tools/jnimarshalmethod-gen/Message.csRemoves generator-specific localized messages.
tools/jnimarshalmethod-gen/App.csRemoves generator app entrypoint and processing pipeline.
tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop/JavaCallableConstructorAttribute.csAdds local test-only attribute type to replace removed Export assembly dependency.
tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop/JavaCallableAttribute.csAdds local test-only attribute type to replace removed Export assembly dependency.
tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop.Tools.JavaCallableWrappers-Tests.csprojStops compiling attribute sources from Java.Interop.Export.
tests/Java.Interop.Tools.Expressions-Tests/Usings.csRemoves global using as the Expressions test project is removed.
tests/Java.Interop.Tools.Expressions-Tests/Java.Interop.Tools.ExpressionsTests/ExpressionAssemblyBuilderTests.csDeletes tests for the removed Expressions toolchain.
tests/Java.Interop.Tools.Expressions-Tests/Java.Interop.Tools.Expressions-Tests.csprojDeletes the Expressions test project.
tests/Java.Interop.Export-Tests/java/net/dot/jni/test/UseJavaCallableExample.javaDeletes Export test Java sources.
tests/Java.Interop.Export-Tests/java/net/dot/jni/test/ExportType.javaDeletes Export test Java sources.
tests/Java.Interop.Export-Tests/Java.Interop/MarshalMemberBuilderTest.csDeletes Export/MarshalMemberBuilder test coverage.
tests/Java.Interop.Export-Tests/Java.Interop/JavaVMFixture.csDeletes fixture used only by Export tests.
tests/Java.Interop.Export-Tests/Java.Interop/JavaCallableExampleTests.csDeletes JavaCallable example tests tied to Export infra.
tests/Java.Interop.Export-Tests/Java.Interop/JavaCallableExample.csDeletes JavaCallable example type tied to Export infra.
tests/Java.Interop.Export-Tests/Java.Interop/ExportTest.csDeletes ExportTest type which relied on MarshalMemberBuilder.
tests/Java.Interop.Export-Tests/Java.Interop.Export-Tests.targetsDeletes MSBuild targets used to build Export test jar and wrappers.
tests/Java.Interop.Export-Tests/Java.Interop.Export-Tests.csprojDeletes Export tests project.
tests/Java.Interop-Tests/Java.Interop/TestType.csStops using MarshalMemberBuilder.CreateMarshalToManagedDelegate(); returns existing delegate directly.
tests/Java.Interop-Tests/Java.Interop/JniRuntimeTest.csRemoves ProxyMarshalMemberBuilder test shim as marshal builder is no longer supported.
tests/Java.Base-Tests/Java.Base/JavaToManagedTests.csAdds explicit native registration methods instead of relying on marshal builder infrastructure.
src/Java.Runtime.Environment/Java.Runtime.Environment.csprojRemoves project reference to Java.Interop.Export.
src/Java.Runtime.Environment/Java.Interop/MonoRuntimeValueManager.csSwitches activation to reflection-based creation instead of CreateConstructActivationPeerFunc().
src/Java.Runtime.Environment/Java.Interop/ManagedValueManager.csRemoves marshal-member-builder activation branch; always uses reflection path.
src/Java.Runtime.Environment/Java.Interop/JreTypeManager.csRemoves marshal-member-builder fallback; now throws if registration isn’t handled explicitly.
src/Java.Interop/Java.Interop/JniRuntime.csRemoves initialization/disposal of marshal member builder.
src/Java.Interop/Java.Interop/JniRuntime.JniMarshalMemberBuilder.csObsoletes marshal member builder APIs; replaces behavior with NotSupportedException.
src/Java.Interop/GlobalSuppressions.csDrops suppression for removed IsDirectMethod analyzer case.
src/Java.Interop.Tools.Expressions/Java.Interop.Tools.Expressions/ExpressionMethodRegistration.csDeletes Expressions helper type.
src/Java.Interop.Tools.Expressions/Java.Interop.Tools.Expressions/ExpressionAssemblyBuilder.csDeletes Expressions-to-IL compiler utility.
src/Java.Interop.Tools.Expressions/Java.Interop.Tools.Expressions/CecilCompilerExpressionVisitor.csDeletes Expressions-to-IL compiler visitor.
src/Java.Interop.Tools.Expressions/Java.Interop.Tools.Expressions.csprojDeletes Expressions project.
src/Java.Interop.Export/Java.Interop/MarshalMemberBuilder.csDeletes Export-side MarshalMemberBuilder implementation.
src/Java.Interop.Export/Java.Interop.Export.csprojDeletes Export assembly project.
samples/Hello-NativeAOTFromJNI/ManagedType.csAdds explicit native registration/marshal method stub instead of post-build generator.
samples/Hello-NativeAOTFromJNI/JavaInteropRuntime.csRemoves UseMarshalMemberBuilder=false usage.
samples/Hello-NativeAOTFromJNI/JavaCallableAttributes.csAdds local attribute definitions for the sample (no Export dependency).
samples/Hello-NativeAOTFromJNI/Hello-NativeAOTFromJNI.targetsRemoves post-build _AddMarshalMethods target.
samples/Hello-NativeAOTFromJNI/Hello-NativeAOTFromJNI.csprojRemoves references to Export + jnimarshalmethod-gen tool projects.
samples/Hello-NativeAOTFromAndroid/JavaInteropRuntime.csRemoves UseMarshalMemberBuilder=false usage.
samples/Hello-NativeAOTFromAndroid/Hello-NativeAOTFromAndroid.targetsRemoves _AddMarshalMethods target and dependency ordering.
samples/Hello-NativeAOTFromAndroid/Hello-NativeAOTFromAndroid.csprojRemoves references to Export + jnimarshalmethod-gen tool projects.
build-tools/automation/templates/core-tests.yamlRemoves CI steps that ran Export tests and marshal-method generator.
MakefileRemoves Export test target and jnimarshalmethod-gen test recipe.
Java.Interop.slnRemoves Export/Expressions/tool projects from the solution.

Comment threadsamples/Hello-NativeAOTFromJNI/ManagedType.cs
Comment threadJava.Interop.sln
@jonathanpeppersjonathanpeppers added the ready-to-review This PR is ready to review/merge, thanks! label Apr 24, 2026

@simonrozsivalsimonrozsival left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

@jonathanpeppers
jonathanpeppers merged commit dedb8f8 into mainApr 27, 2026
6 checks passed
@jonathanpeppers
jonathanpeppers deleted the jonathanpeppers/dev-peppers-remove-jni-marshal-methods branch April 27, 2026 17:20
jonathanpeppers added a commit to dotnet/android that referenced this pull request Apr 27, 2026
…et/java-interop#1405
- Remove UseMarshalMemberBuilder = false from AndroidRuntime and
NativeAOT JavaInteropRuntime (property is now obsolete/no-op).
- Remove deleted Java.Interop.Export and
Xamarin.Android.Tools.JniMarshalMethodGenerator projects from
Xamarin.Android.sln.
- Bump external/Java.Interop submodule to PR 1405 head.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jonathanpeppers added a commit to dotnet/android that referenced this pull request Apr 28, 2026
### Remove UseMarshalMemberBuilder and bump external/Java.Interop to dotnet/java-interop#1405
- Remove UseMarshalMemberBuilder = false from AndroidRuntime and
NativeAOT JavaInteropRuntime (property is now obsolete/no-op).
- Remove deleted Java.Interop.Export and
Xamarin.Android.Tools.JniMarshalMethodGenerator projects from
Xamarin.Android.sln.
- Bump external/Java.Interop submodule to PR 1405 head.
### Copy java-interop.jar to SDK output directory
Add a ProjectReference to Java.Interop.csproj (with
ReferenceOutputAssembly=false) from Xamarin.Android.Build.Tasks.csproj
so that `java-interop.jar` (a Content item in Java.Interop.csproj) gets
copied to the output directory. Previously this happened transitively
through Java.Interop.Export which is now deleted.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
simonrozsival added a commit to dotnet/android that referenced this pull request May 11, 2026
…emap
[JniAddNativeMethodRegistrationAttribute] is a legacy Java.Interop API whose
primary consumer — the jnimarshalmethod-gen build-time generator — was
removed in dotnet/java-interop#1405. The trimmable typemap deliberately does
not support this attribute.
When the scanner detects the attribute on any method, the generator emits
XA4251 telling the developer to either avoid it or switch off the trimmable
typemap (for example, by using the 'llvm-ir' type map implementation) and
report the scenario at https://github.com/dotnet/android/issues. The build
fails via TaskLoggingHelper.HasLoggedErrors.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jonathanpeppers added a commit to dotnet/android that referenced this pull request May 14, 2026
…ith XA4251 (#11274)
### Use trimmable Java proxy runtime sources
Add trimmable-specific java_runtime jars that replace Java.Interop's JavaProxyObject and JavaProxyThrowable sources only for the trimmable typemap path. Keep the existing runtime jars on Java.Interop's native-registration behavior and select the trimmable jars when _AndroidTypeMapImplementation is trimmable.
Re-enable the affected Java.Interop runtime tests and add focused coverage for JavaProxyObject marshaling/object methods under the trimmable typemap path.
### Use trimmable virtual-constructor fixtures
Enable the Java.Interop virtual-constructor tests in the trimmable typemap lane by swapping in Android-owned Java fixtures that use Runtime.registerNatives and generated n_* callbacks instead of ManagedPeer.
Teach the trimmable typemap scanner/model to emit native registrations for hand-written Java peers that opt into JniAddNativeMethodRegistrationAttribute.
### Address Java proxy review comments
Use repository Java formatting for trimmable proxy sources and strengthen the proxy hashCode test so it compares against Java identityHashCode instead of itself.
### Simplify trimmable runtime artifacts
Drop stale _net6 Java runtime artifact names and collapse the trimmable runtime jar/dex to a single shared artifact for CoreCLR and NativeAOT.
### Drop unrelated obsolete-jar cleanup from java-runtime.targets and TrimmableTypeMapBuildTests
This cleanup is not related to fixing InvokeVirtualFromConstructorTests
and belongs in a separate change.
### Refuse [JniAddNativeMethodRegistrationAttribute] in the trimmable typemap
[JniAddNativeMethodRegistrationAttribute] is a legacy Java.Interop API whose
primary consumer — the jnimarshalmethod-gen build-time generator — was
removed in dotnet/java-interop#1405. The trimmable typemap deliberately does
not support this attribute.
When the scanner detects the attribute on any method, the generator emits
XA4251 telling the developer to either avoid it or switch off the trimmable
typemap (for example, by using the 'llvm-ir' type map implementation) and
report the scenario at https://github.com/dotnet/android/issues. The build
fails via TaskLoggingHelper.HasLoggedErrors.
### Move XA4251 reporting into JavaPeerScanner
Address review feedback:
- Drop JavaPeerInfo.HasJniAddNativeMethodRegistrationAttribute. The scanner
now takes an optional ITrimmableTypeMapLogger and reports XA4251 directly
when it encounters the attribute, instead of propagating a bool the rest
of the pipeline doesn't otherwise need.
- Drop the orchestrator's post-scan loop; TrimmableTypeMapGenerator just
passes its logger into JavaPeerScanner.
- Reset external/Java.Interop and external/xamarin-android-tools to the
SHAs on main; this PR doesn't need either submodule moved.
### Restore tests/Mono.Android-Tests/Java.Interop-Tests/java-trimmable/net/dot/jni/test/GetThis.java
This file is unrelated to the XA4251 work; it was accidentally removed during
an earlier 'git rm -r java-trimmable' cleanup. It's still needed by
JavaObjectTest.DisposeAccessesThis under the trimmable typemap.
### Exclude InvokeVirtualFromConstructor fixtures for trimmable
The upstream Java.Interop test fixture CallVirtualFromConstructorDerived
uses [JniAddNativeMethodRegistrationAttribute]. Now that the trimmable
typemap refuses that attribute with XA4251, the offending sources need to
be excluded from the test assembly when building for the trimmable type
map; otherwise the build cannot reach the device tests at all.
Validated locally:
ANDROID_SERIAL=emulator-5554 MSBUILDDISABLENODEREUSE=1 \
./dotnet-local.sh build \
tests/Mono.Android-Tests/Mono.Android-Tests/Mono.Android.NET-Tests.csproj \
-t:RunTestApp -c Release \
-p:_AndroidTypeMapImplementation=trimmable \
-p:UseMonoRuntime=false -nr:false -m:1
TestResult-Mono.Android.NET_Tests-ReleaseCoreCLRTrimmable.xml: 888 total,
0 errors, 0 failures, 21 ignored.
### Detect [JniAddNativeMethodRegistrationAttribute] on non-peer types too
Code-review caught that the prior placement of the XA4251 check sat *after*
the scanner's per-type filtering, so a type carrying the attribute but no
[Register] (and not extending a Java peer) would slip past the diagnostic
and the build would silently succeed.
Hoist the check to immediately after the <Module> skip so it fires uniformly
for every non-<Module> type, regardless of whether the type would otherwise
have been added to the typemap. Add a NonPeerNativeRegistration fixture to
the scanner test to guard the regression.
### Skip per-method XA4251 walk when assembly doesn't reference the attribute
Address Copilot reviewer feedback on the per-type method-attribute walk.
AssemblyIndex.Build now does a cheap pass over the TypeReferences and
TypeDefinitions tables to set MayUseJniAddNativeMethodRegistrationAttribute,
and the scanner short-circuits the per-method walk in the overwhelmingly
common case where the assembly neither imports nor declares the attribute.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Jonathan Peppers <jonathan.peppers@microsoft.com>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators May 28, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

ready-to-reviewThis PR is ready to review/merge, thanks!

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@jonathanpeppers@simonrozsival
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
This repository was archived by the owner on Aug 27, 2026. It is now read-only.

Remove $(AndroidGenerateJniMarshalMethods) support - #1405

Merged
jonathanpeppers merged 5 commits into
mainfrom
jonathanpeppers/dev-peppers-remove-jni-marshal-methods
Apr 27, 2026
Merged

Remove $(AndroidGenerateJniMarshalMethods) support#1405
jonathanpeppers merged 5 commits into
mainfrom
jonathanpeppers/dev-peppers-remove-jni-marshal-methods

Conversation

@jonathanpeppers

Copy link
Copy Markdown
Member

Context: dotnet/android@4296716

Summary

Remove the $(AndroidGenerateJniMarshalMethods) infrastructure from java-interop, which was already removed from dotnet/android.

44 files changed, 54 insertions, 5,513 deletions

What's removed

  • tools/jnimarshalmethod-gen/ — the marshal method generator tool
  • src/Java.Interop.Export/MarshalMemberBuilder implementation + [JavaCallable] attributes
  • tests/Java.Interop.Export-Tests/ — tests for the above
  • src/Java.Interop.Tools.Expressions/ — Expression-to-IL compiler used only by jnimarshalmethod-gen
  • tests/Java.Interop.Tools.Expressions-Tests/ — tests for the above

What's kept (marked [Obsolete])

All public APIs in Java.Interop.dll are retained but obsoleted:

  • CreationOptions.UseMarshalMemberBuilder
  • CreationOptions.MarshalMemberBuilder
  • JniRuntime.MarshalMemberBuilder
  • JniRuntime.JniMarshalMemberBuilder abstract class + all members

Non-abstract methods now throw NotSupportedException.

Runtime simplification

  • JreTypeManager.RegisterNativeMembers — removed the MarshalMemberBuilder fallback path; now throws if TryRegisterNativeMembers fails
  • ManagedValueManager.ActivatePeer — always uses reflection activation
  • MonoRuntimeValueManager.ActivatePeer — uses reflection activation instead of MarshalMemberBuilder.CreateConstructActivationPeerFunc

dotnet/android impact

dotnet/android sets UseMarshalMemberBuilder = false in two places. After this change, those lines should be removed (they'll generate [Obsolete] warnings):

  • src/Mono.Android/Android.Runtime/AndroidRuntime.cs
  • src/Microsoft.Android.Runtime.NativeAOT/Android.Runtime.NativeAOT/JavaInteropRuntime.cs

Build & test

  • Solution builds successfully
  • Java.Interop-Tests: 665 passed, 0 failed
  • JCW-Tests: 47 passed, 0 failed

Delete the jnimarshalmethod-gen tool, Java.Interop.Export library,
Java.Interop.Export-Tests, and Java.Interop.Tools.Expressions projects.
All public APIs in Java.Interop.dll (JniMarshalMemberBuilder,
CreationOptions.UseMarshalMemberBuilder, etc.) are retained but marked
[Obsolete] with no-op implementations.
Runtime code in JreTypeManager, ManagedValueManager, and
MonoRuntimeValueManager is simplified to remove MarshalMemberBuilder
fallback paths.
NativeAOT samples, Makefile, and CI pipeline are updated accordingly.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jonathanpeppers added a commit to dotnet/android that referenced this pull request Apr 16, 2026
Bump \�xternal/Java.Interop\ to dotnet/java-interop#1405, which removes
\Java.Interop.Export\, \jnimarshalmethod-gen\, and
\Java.Interop.Tools.Expressions\.
Changes in dotnet/android:
- Remove \UseMarshalMemberBuilder = false\ from AndroidRuntime and
NativeAOT JavaInteropRuntime (property is now obsolete/no-op).
- Remove deleted \Java.Interop.Export\ and
\Xamarin.Android.Tools.JniMarshalMethodGenerator\ projects from
\Xamarin.Android.sln\.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…eManager trim warnings
- JreTypeManager: Simplify RegisterNativeMembers to return early when
methods is empty (types like JavaProxyThrowable register with no
methods), and throw for non-empty methods without static registration.
- MonoRuntimeValueManager: Add trim suppression attributes for
GetUninitializedObject call to fix NativeAOT publish errors.
- Java.Base-Tests: Add explicit marshal methods and static registration
to MyRunnable and MyIntConsumer test types, since dynamic marshal
method generation via MarshalMemberBuilder is no longer available.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jonathanpeppers
jonathanpeppersforce-pushed the jonathanpeppers/dev-peppers-remove-jni-marshal-methods branch from 01256d8 to 5cb82cdCompareApril 17, 2026 13:51
jonathanpeppersand others added 3 commits April 17, 2026 11:58
…hal methods
ManagedType.cs used [JavaCallable] attributes which relied on the
now-removed jnimarshalmethod-gen tool. Replace with explicit n_*
marshal methods and [JniAddNativeMethodRegistration] static registration.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ration
jcw-gen uses Cecil to find [JavaCallable] and [JavaCallableConstructor]
by attribute name to emit Java-side methods. These attributes must still
exist at compile time for the JCW to include getString() and the
constructor.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
NativeAOT requires delegate types used for JNI callbacks to have
[UnmanagedFunctionPointer] for proper marshalling data generation.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jonathanpeppers added a commit to dotnet/android that referenced this pull request Apr 22, 2026
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jonathanpeppers added a commit to dotnet/android that referenced this pull request Apr 22, 2026
…et/java-interop#1405
- Remove UseMarshalMemberBuilder = false from AndroidRuntime and
NativeAOT JavaInteropRuntime (property is now obsolete/no-op).
- Remove deleted Java.Interop.Export and
Xamarin.Android.Tools.JniMarshalMethodGenerator projects from
Xamarin.Android.sln.
- Bump external/Java.Interop submodule to PR 1405 head.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jonathanpeppers

Copy link
Copy Markdown
MemberAuthor

The dotnet/android test PR looks OK:

There are some flaky tests, but everything builds.

@jonathanpeppers
jonathanpeppers marked this pull request as ready for review April 23, 2026 18:27
CopilotAI review requested due to automatic review settings April 23, 2026 18:27

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR removes the legacy $(AndroidGenerateJniMarshalMethods)-driven marshal-method generation infrastructure from java-interop, aligning with the earlier removal in dotnet/android, while keeping the public surface area in Java.Interop.dll as [Obsolete] stubs that now throw NotSupportedException.

Changes:

  • Removes the jnimarshalmethod-gen tool and the Java.Interop.Export / Java.Interop.Tools.Expressions projects (plus associated tests and pipeline hooks).
  • Simplifies runtime activation/registration paths to rely on reflection and explicit [JniAddNativeMethodRegistration] patterns instead of MarshalMemberBuilder.
  • Updates samples and tests to no longer depend on Java.Interop.Export and generated marshal methods.

Reviewed changes

Copilot reviewed 44 out of 46 changed files in this pull request and generated 2 comments.

Show a summary per file
FileDescription
tools/jnimarshalmethod-gen/Xamarin.Android.Tools.JniMarshalMethodGenerator.csprojDeletes the marshal-method generator tool project.
tools/jnimarshalmethod-gen/TypeMover.csRemoves type-moving logic used by the generator.
tools/jnimarshalmethod-gen/Message.csRemoves generator-specific localized messages.
tools/jnimarshalmethod-gen/App.csRemoves generator app entrypoint and processing pipeline.
tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop/JavaCallableConstructorAttribute.csAdds local test-only attribute type to replace removed Export assembly dependency.
tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop/JavaCallableAttribute.csAdds local test-only attribute type to replace removed Export assembly dependency.
tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop.Tools.JavaCallableWrappers-Tests.csprojStops compiling attribute sources from Java.Interop.Export.
tests/Java.Interop.Tools.Expressions-Tests/Usings.csRemoves global using as the Expressions test project is removed.
tests/Java.Interop.Tools.Expressions-Tests/Java.Interop.Tools.ExpressionsTests/ExpressionAssemblyBuilderTests.csDeletes tests for the removed Expressions toolchain.
tests/Java.Interop.Tools.Expressions-Tests/Java.Interop.Tools.Expressions-Tests.csprojDeletes the Expressions test project.
tests/Java.Interop.Export-Tests/java/net/dot/jni/test/UseJavaCallableExample.javaDeletes Export test Java sources.
tests/Java.Interop.Export-Tests/java/net/dot/jni/test/ExportType.javaDeletes Export test Java sources.
tests/Java.Interop.Export-Tests/Java.Interop/MarshalMemberBuilderTest.csDeletes Export/MarshalMemberBuilder test coverage.
tests/Java.Interop.Export-Tests/Java.Interop/JavaVMFixture.csDeletes fixture used only by Export tests.
tests/Java.Interop.Export-Tests/Java.Interop/JavaCallableExampleTests.csDeletes JavaCallable example tests tied to Export infra.
tests/Java.Interop.Export-Tests/Java.Interop/JavaCallableExample.csDeletes JavaCallable example type tied to Export infra.
tests/Java.Interop.Export-Tests/Java.Interop/ExportTest.csDeletes ExportTest type which relied on MarshalMemberBuilder.
tests/Java.Interop.Export-Tests/Java.Interop.Export-Tests.targetsDeletes MSBuild targets used to build Export test jar and wrappers.
tests/Java.Interop.Export-Tests/Java.Interop.Export-Tests.csprojDeletes Export tests project.
tests/Java.Interop-Tests/Java.Interop/TestType.csStops using MarshalMemberBuilder.CreateMarshalToManagedDelegate(); returns existing delegate directly.
tests/Java.Interop-Tests/Java.Interop/JniRuntimeTest.csRemoves ProxyMarshalMemberBuilder test shim as marshal builder is no longer supported.
tests/Java.Base-Tests/Java.Base/JavaToManagedTests.csAdds explicit native registration methods instead of relying on marshal builder infrastructure.
src/Java.Runtime.Environment/Java.Runtime.Environment.csprojRemoves project reference to Java.Interop.Export.
src/Java.Runtime.Environment/Java.Interop/MonoRuntimeValueManager.csSwitches activation to reflection-based creation instead of CreateConstructActivationPeerFunc().
src/Java.Runtime.Environment/Java.Interop/ManagedValueManager.csRemoves marshal-member-builder activation branch; always uses reflection path.
src/Java.Runtime.Environment/Java.Interop/JreTypeManager.csRemoves marshal-member-builder fallback; now throws if registration isn’t handled explicitly.
src/Java.Interop/Java.Interop/JniRuntime.csRemoves initialization/disposal of marshal member builder.
src/Java.Interop/Java.Interop/JniRuntime.JniMarshalMemberBuilder.csObsoletes marshal member builder APIs; replaces behavior with NotSupportedException.
src/Java.Interop/GlobalSuppressions.csDrops suppression for removed IsDirectMethod analyzer case.
src/Java.Interop.Tools.Expressions/Java.Interop.Tools.Expressions/ExpressionMethodRegistration.csDeletes Expressions helper type.
src/Java.Interop.Tools.Expressions/Java.Interop.Tools.Expressions/ExpressionAssemblyBuilder.csDeletes Expressions-to-IL compiler utility.
src/Java.Interop.Tools.Expressions/Java.Interop.Tools.Expressions/CecilCompilerExpressionVisitor.csDeletes Expressions-to-IL compiler visitor.
src/Java.Interop.Tools.Expressions/Java.Interop.Tools.Expressions.csprojDeletes Expressions project.
src/Java.Interop.Export/Java.Interop/MarshalMemberBuilder.csDeletes Export-side MarshalMemberBuilder implementation.
src/Java.Interop.Export/Java.Interop.Export.csprojDeletes Export assembly project.
samples/Hello-NativeAOTFromJNI/ManagedType.csAdds explicit native registration/marshal method stub instead of post-build generator.
samples/Hello-NativeAOTFromJNI/JavaInteropRuntime.csRemoves UseMarshalMemberBuilder=false usage.
samples/Hello-NativeAOTFromJNI/JavaCallableAttributes.csAdds local attribute definitions for the sample (no Export dependency).
samples/Hello-NativeAOTFromJNI/Hello-NativeAOTFromJNI.targetsRemoves post-build _AddMarshalMethods target.
samples/Hello-NativeAOTFromJNI/Hello-NativeAOTFromJNI.csprojRemoves references to Export + jnimarshalmethod-gen tool projects.
samples/Hello-NativeAOTFromAndroid/JavaInteropRuntime.csRemoves UseMarshalMemberBuilder=false usage.
samples/Hello-NativeAOTFromAndroid/Hello-NativeAOTFromAndroid.targetsRemoves _AddMarshalMethods target and dependency ordering.
samples/Hello-NativeAOTFromAndroid/Hello-NativeAOTFromAndroid.csprojRemoves references to Export + jnimarshalmethod-gen tool projects.
build-tools/automation/templates/core-tests.yamlRemoves CI steps that ran Export tests and marshal-method generator.
MakefileRemoves Export test target and jnimarshalmethod-gen test recipe.
Java.Interop.slnRemoves Export/Expressions/tool projects from the solution.

Comment threadsamples/Hello-NativeAOTFromJNI/ManagedType.cs
Comment threadJava.Interop.sln
@jonathanpeppersjonathanpeppers added the ready-to-review This PR is ready to review/merge, thanks! label Apr 24, 2026

@simonrozsivalsimonrozsival left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

@jonathanpeppers
jonathanpeppers merged commit dedb8f8 into mainApr 27, 2026
6 checks passed
@jonathanpeppers
jonathanpeppers deleted the jonathanpeppers/dev-peppers-remove-jni-marshal-methods branch April 27, 2026 17:20
jonathanpeppers added a commit to dotnet/android that referenced this pull request Apr 27, 2026
…et/java-interop#1405
- Remove UseMarshalMemberBuilder = false from AndroidRuntime and
NativeAOT JavaInteropRuntime (property is now obsolete/no-op).
- Remove deleted Java.Interop.Export and
Xamarin.Android.Tools.JniMarshalMethodGenerator projects from
Xamarin.Android.sln.
- Bump external/Java.Interop submodule to PR 1405 head.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jonathanpeppers added a commit to dotnet/android that referenced this pull request Apr 28, 2026
### Remove UseMarshalMemberBuilder and bump external/Java.Interop to dotnet/java-interop#1405
- Remove UseMarshalMemberBuilder = false from AndroidRuntime and
NativeAOT JavaInteropRuntime (property is now obsolete/no-op).
- Remove deleted Java.Interop.Export and
Xamarin.Android.Tools.JniMarshalMethodGenerator projects from
Xamarin.Android.sln.
- Bump external/Java.Interop submodule to PR 1405 head.
### Copy java-interop.jar to SDK output directory
Add a ProjectReference to Java.Interop.csproj (with
ReferenceOutputAssembly=false) from Xamarin.Android.Build.Tasks.csproj
so that `java-interop.jar` (a Content item in Java.Interop.csproj) gets
copied to the output directory. Previously this happened transitively
through Java.Interop.Export which is now deleted.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
simonrozsival added a commit to dotnet/android that referenced this pull request May 11, 2026
…emap
[JniAddNativeMethodRegistrationAttribute] is a legacy Java.Interop API whose
primary consumer — the jnimarshalmethod-gen build-time generator — was
removed in dotnet/java-interop#1405. The trimmable typemap deliberately does
not support this attribute.
When the scanner detects the attribute on any method, the generator emits
XA4251 telling the developer to either avoid it or switch off the trimmable
typemap (for example, by using the 'llvm-ir' type map implementation) and
report the scenario at https://github.com/dotnet/android/issues. The build
fails via TaskLoggingHelper.HasLoggedErrors.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jonathanpeppers added a commit to dotnet/android that referenced this pull request May 14, 2026
…ith XA4251 (#11274)
### Use trimmable Java proxy runtime sources
Add trimmable-specific java_runtime jars that replace Java.Interop's JavaProxyObject and JavaProxyThrowable sources only for the trimmable typemap path. Keep the existing runtime jars on Java.Interop's native-registration behavior and select the trimmable jars when _AndroidTypeMapImplementation is trimmable.
Re-enable the affected Java.Interop runtime tests and add focused coverage for JavaProxyObject marshaling/object methods under the trimmable typemap path.
### Use trimmable virtual-constructor fixtures
Enable the Java.Interop virtual-constructor tests in the trimmable typemap lane by swapping in Android-owned Java fixtures that use Runtime.registerNatives and generated n_* callbacks instead of ManagedPeer.
Teach the trimmable typemap scanner/model to emit native registrations for hand-written Java peers that opt into JniAddNativeMethodRegistrationAttribute.
### Address Java proxy review comments
Use repository Java formatting for trimmable proxy sources and strengthen the proxy hashCode test so it compares against Java identityHashCode instead of itself.
### Simplify trimmable runtime artifacts
Drop stale _net6 Java runtime artifact names and collapse the trimmable runtime jar/dex to a single shared artifact for CoreCLR and NativeAOT.
### Drop unrelated obsolete-jar cleanup from java-runtime.targets and TrimmableTypeMapBuildTests
This cleanup is not related to fixing InvokeVirtualFromConstructorTests
and belongs in a separate change.
### Refuse [JniAddNativeMethodRegistrationAttribute] in the trimmable typemap
[JniAddNativeMethodRegistrationAttribute] is a legacy Java.Interop API whose
primary consumer — the jnimarshalmethod-gen build-time generator — was
removed in dotnet/java-interop#1405. The trimmable typemap deliberately does
not support this attribute.
When the scanner detects the attribute on any method, the generator emits
XA4251 telling the developer to either avoid it or switch off the trimmable
typemap (for example, by using the 'llvm-ir' type map implementation) and
report the scenario at https://github.com/dotnet/android/issues. The build
fails via TaskLoggingHelper.HasLoggedErrors.
### Move XA4251 reporting into JavaPeerScanner
Address review feedback:
- Drop JavaPeerInfo.HasJniAddNativeMethodRegistrationAttribute. The scanner
now takes an optional ITrimmableTypeMapLogger and reports XA4251 directly
when it encounters the attribute, instead of propagating a bool the rest
of the pipeline doesn't otherwise need.
- Drop the orchestrator's post-scan loop; TrimmableTypeMapGenerator just
passes its logger into JavaPeerScanner.
- Reset external/Java.Interop and external/xamarin-android-tools to the
SHAs on main; this PR doesn't need either submodule moved.
### Restore tests/Mono.Android-Tests/Java.Interop-Tests/java-trimmable/net/dot/jni/test/GetThis.java
This file is unrelated to the XA4251 work; it was accidentally removed during
an earlier 'git rm -r java-trimmable' cleanup. It's still needed by
JavaObjectTest.DisposeAccessesThis under the trimmable typemap.
### Exclude InvokeVirtualFromConstructor fixtures for trimmable
The upstream Java.Interop test fixture CallVirtualFromConstructorDerived
uses [JniAddNativeMethodRegistrationAttribute]. Now that the trimmable
typemap refuses that attribute with XA4251, the offending sources need to
be excluded from the test assembly when building for the trimmable type
map; otherwise the build cannot reach the device tests at all.
Validated locally:
ANDROID_SERIAL=emulator-5554 MSBUILDDISABLENODEREUSE=1 \
./dotnet-local.sh build \
tests/Mono.Android-Tests/Mono.Android-Tests/Mono.Android.NET-Tests.csproj \
-t:RunTestApp -c Release \
-p:_AndroidTypeMapImplementation=trimmable \
-p:UseMonoRuntime=false -nr:false -m:1
TestResult-Mono.Android.NET_Tests-ReleaseCoreCLRTrimmable.xml: 888 total,
0 errors, 0 failures, 21 ignored.
### Detect [JniAddNativeMethodRegistrationAttribute] on non-peer types too
Code-review caught that the prior placement of the XA4251 check sat *after*
the scanner's per-type filtering, so a type carrying the attribute but no
[Register] (and not extending a Java peer) would slip past the diagnostic
and the build would silently succeed.
Hoist the check to immediately after the <Module> skip so it fires uniformly
for every non-<Module> type, regardless of whether the type would otherwise
have been added to the typemap. Add a NonPeerNativeRegistration fixture to
the scanner test to guard the regression.
### Skip per-method XA4251 walk when assembly doesn't reference the attribute
Address Copilot reviewer feedback on the per-type method-attribute walk.
AssemblyIndex.Build now does a cheap pass over the TypeReferences and
TypeDefinitions tables to set MayUseJniAddNativeMethodRegistrationAttribute,
and the scanner short-circuits the per-method walk in the overwhelmingly
common case where the assembly neither imports nor declares the attribute.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Jonathan Peppers <jonathan.peppers@microsoft.com>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators May 28, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

ready-to-reviewThis PR is ready to review/merge, thanks!

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@jonathanpeppers@simonrozsival
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
This repository was archived by the owner on Aug 27, 2026. It is now read-only.

Remove $(AndroidGenerateJniMarshalMethods) support - #1405

Merged
jonathanpeppers merged 5 commits into
mainfrom
jonathanpeppers/dev-peppers-remove-jni-marshal-methods
Apr 27, 2026
Merged

Remove $(AndroidGenerateJniMarshalMethods) support#1405
jonathanpeppers merged 5 commits into
mainfrom
jonathanpeppers/dev-peppers-remove-jni-marshal-methods

Conversation

@jonathanpeppers

Copy link
Copy Markdown
Member

Context: dotnet/android@4296716

Summary

Remove the $(AndroidGenerateJniMarshalMethods) infrastructure from java-interop, which was already removed from dotnet/android.

44 files changed, 54 insertions, 5,513 deletions

What's removed

  • tools/jnimarshalmethod-gen/ — the marshal method generator tool
  • src/Java.Interop.Export/MarshalMemberBuilder implementation + [JavaCallable] attributes
  • tests/Java.Interop.Export-Tests/ — tests for the above
  • src/Java.Interop.Tools.Expressions/ — Expression-to-IL compiler used only by jnimarshalmethod-gen
  • tests/Java.Interop.Tools.Expressions-Tests/ — tests for the above

What's kept (marked [Obsolete])

All public APIs in Java.Interop.dll are retained but obsoleted:

  • CreationOptions.UseMarshalMemberBuilder
  • CreationOptions.MarshalMemberBuilder
  • JniRuntime.MarshalMemberBuilder
  • JniRuntime.JniMarshalMemberBuilder abstract class + all members

Non-abstract methods now throw NotSupportedException.

Runtime simplification

  • JreTypeManager.RegisterNativeMembers — removed the MarshalMemberBuilder fallback path; now throws if TryRegisterNativeMembers fails
  • ManagedValueManager.ActivatePeer — always uses reflection activation
  • MonoRuntimeValueManager.ActivatePeer — uses reflection activation instead of MarshalMemberBuilder.CreateConstructActivationPeerFunc

dotnet/android impact

dotnet/android sets UseMarshalMemberBuilder = false in two places. After this change, those lines should be removed (they'll generate [Obsolete] warnings):

  • src/Mono.Android/Android.Runtime/AndroidRuntime.cs
  • src/Microsoft.Android.Runtime.NativeAOT/Android.Runtime.NativeAOT/JavaInteropRuntime.cs

Build & test

  • Solution builds successfully
  • Java.Interop-Tests: 665 passed, 0 failed
  • JCW-Tests: 47 passed, 0 failed

Delete the jnimarshalmethod-gen tool, Java.Interop.Export library,
Java.Interop.Export-Tests, and Java.Interop.Tools.Expressions projects.
All public APIs in Java.Interop.dll (JniMarshalMemberBuilder,
CreationOptions.UseMarshalMemberBuilder, etc.) are retained but marked
[Obsolete] with no-op implementations.
Runtime code in JreTypeManager, ManagedValueManager, and
MonoRuntimeValueManager is simplified to remove MarshalMemberBuilder
fallback paths.
NativeAOT samples, Makefile, and CI pipeline are updated accordingly.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jonathanpeppers added a commit to dotnet/android that referenced this pull request Apr 16, 2026
Bump \�xternal/Java.Interop\ to dotnet/java-interop#1405, which removes
\Java.Interop.Export\, \jnimarshalmethod-gen\, and
\Java.Interop.Tools.Expressions\.
Changes in dotnet/android:
- Remove \UseMarshalMemberBuilder = false\ from AndroidRuntime and
NativeAOT JavaInteropRuntime (property is now obsolete/no-op).
- Remove deleted \Java.Interop.Export\ and
\Xamarin.Android.Tools.JniMarshalMethodGenerator\ projects from
\Xamarin.Android.sln\.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…eManager trim warnings
- JreTypeManager: Simplify RegisterNativeMembers to return early when
methods is empty (types like JavaProxyThrowable register with no
methods), and throw for non-empty methods without static registration.
- MonoRuntimeValueManager: Add trim suppression attributes for
GetUninitializedObject call to fix NativeAOT publish errors.
- Java.Base-Tests: Add explicit marshal methods and static registration
to MyRunnable and MyIntConsumer test types, since dynamic marshal
method generation via MarshalMemberBuilder is no longer available.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jonathanpeppers
jonathanpeppersforce-pushed the jonathanpeppers/dev-peppers-remove-jni-marshal-methods branch from 01256d8 to 5cb82cdCompareApril 17, 2026 13:51
jonathanpeppersand others added 3 commits April 17, 2026 11:58
…hal methods
ManagedType.cs used [JavaCallable] attributes which relied on the
now-removed jnimarshalmethod-gen tool. Replace with explicit n_*
marshal methods and [JniAddNativeMethodRegistration] static registration.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ration
jcw-gen uses Cecil to find [JavaCallable] and [JavaCallableConstructor]
by attribute name to emit Java-side methods. These attributes must still
exist at compile time for the JCW to include getString() and the
constructor.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
NativeAOT requires delegate types used for JNI callbacks to have
[UnmanagedFunctionPointer] for proper marshalling data generation.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jonathanpeppers added a commit to dotnet/android that referenced this pull request Apr 22, 2026
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jonathanpeppers added a commit to dotnet/android that referenced this pull request Apr 22, 2026
…et/java-interop#1405
- Remove UseMarshalMemberBuilder = false from AndroidRuntime and
NativeAOT JavaInteropRuntime (property is now obsolete/no-op).
- Remove deleted Java.Interop.Export and
Xamarin.Android.Tools.JniMarshalMethodGenerator projects from
Xamarin.Android.sln.
- Bump external/Java.Interop submodule to PR 1405 head.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jonathanpeppers

Copy link
Copy Markdown
MemberAuthor

The dotnet/android test PR looks OK:

There are some flaky tests, but everything builds.

@jonathanpeppers
jonathanpeppers marked this pull request as ready for review April 23, 2026 18:27
CopilotAI review requested due to automatic review settings April 23, 2026 18:27

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR removes the legacy $(AndroidGenerateJniMarshalMethods)-driven marshal-method generation infrastructure from java-interop, aligning with the earlier removal in dotnet/android, while keeping the public surface area in Java.Interop.dll as [Obsolete] stubs that now throw NotSupportedException.

Changes:

  • Removes the jnimarshalmethod-gen tool and the Java.Interop.Export / Java.Interop.Tools.Expressions projects (plus associated tests and pipeline hooks).
  • Simplifies runtime activation/registration paths to rely on reflection and explicit [JniAddNativeMethodRegistration] patterns instead of MarshalMemberBuilder.
  • Updates samples and tests to no longer depend on Java.Interop.Export and generated marshal methods.

Reviewed changes

Copilot reviewed 44 out of 46 changed files in this pull request and generated 2 comments.

Show a summary per file
FileDescription
tools/jnimarshalmethod-gen/Xamarin.Android.Tools.JniMarshalMethodGenerator.csprojDeletes the marshal-method generator tool project.
tools/jnimarshalmethod-gen/TypeMover.csRemoves type-moving logic used by the generator.
tools/jnimarshalmethod-gen/Message.csRemoves generator-specific localized messages.
tools/jnimarshalmethod-gen/App.csRemoves generator app entrypoint and processing pipeline.
tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop/JavaCallableConstructorAttribute.csAdds local test-only attribute type to replace removed Export assembly dependency.
tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop/JavaCallableAttribute.csAdds local test-only attribute type to replace removed Export assembly dependency.
tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop.Tools.JavaCallableWrappers-Tests.csprojStops compiling attribute sources from Java.Interop.Export.
tests/Java.Interop.Tools.Expressions-Tests/Usings.csRemoves global using as the Expressions test project is removed.
tests/Java.Interop.Tools.Expressions-Tests/Java.Interop.Tools.ExpressionsTests/ExpressionAssemblyBuilderTests.csDeletes tests for the removed Expressions toolchain.
tests/Java.Interop.Tools.Expressions-Tests/Java.Interop.Tools.Expressions-Tests.csprojDeletes the Expressions test project.
tests/Java.Interop.Export-Tests/java/net/dot/jni/test/UseJavaCallableExample.javaDeletes Export test Java sources.
tests/Java.Interop.Export-Tests/java/net/dot/jni/test/ExportType.javaDeletes Export test Java sources.
tests/Java.Interop.Export-Tests/Java.Interop/MarshalMemberBuilderTest.csDeletes Export/MarshalMemberBuilder test coverage.
tests/Java.Interop.Export-Tests/Java.Interop/JavaVMFixture.csDeletes fixture used only by Export tests.
tests/Java.Interop.Export-Tests/Java.Interop/JavaCallableExampleTests.csDeletes JavaCallable example tests tied to Export infra.
tests/Java.Interop.Export-Tests/Java.Interop/JavaCallableExample.csDeletes JavaCallable example type tied to Export infra.
tests/Java.Interop.Export-Tests/Java.Interop/ExportTest.csDeletes ExportTest type which relied on MarshalMemberBuilder.
tests/Java.Interop.Export-Tests/Java.Interop.Export-Tests.targetsDeletes MSBuild targets used to build Export test jar and wrappers.
tests/Java.Interop.Export-Tests/Java.Interop.Export-Tests.csprojDeletes Export tests project.
tests/Java.Interop-Tests/Java.Interop/TestType.csStops using MarshalMemberBuilder.CreateMarshalToManagedDelegate(); returns existing delegate directly.
tests/Java.Interop-Tests/Java.Interop/JniRuntimeTest.csRemoves ProxyMarshalMemberBuilder test shim as marshal builder is no longer supported.
tests/Java.Base-Tests/Java.Base/JavaToManagedTests.csAdds explicit native registration methods instead of relying on marshal builder infrastructure.
src/Java.Runtime.Environment/Java.Runtime.Environment.csprojRemoves project reference to Java.Interop.Export.
src/Java.Runtime.Environment/Java.Interop/MonoRuntimeValueManager.csSwitches activation to reflection-based creation instead of CreateConstructActivationPeerFunc().
src/Java.Runtime.Environment/Java.Interop/ManagedValueManager.csRemoves marshal-member-builder activation branch; always uses reflection path.
src/Java.Runtime.Environment/Java.Interop/JreTypeManager.csRemoves marshal-member-builder fallback; now throws if registration isn’t handled explicitly.
src/Java.Interop/Java.Interop/JniRuntime.csRemoves initialization/disposal of marshal member builder.
src/Java.Interop/Java.Interop/JniRuntime.JniMarshalMemberBuilder.csObsoletes marshal member builder APIs; replaces behavior with NotSupportedException.
src/Java.Interop/GlobalSuppressions.csDrops suppression for removed IsDirectMethod analyzer case.
src/Java.Interop.Tools.Expressions/Java.Interop.Tools.Expressions/ExpressionMethodRegistration.csDeletes Expressions helper type.
src/Java.Interop.Tools.Expressions/Java.Interop.Tools.Expressions/ExpressionAssemblyBuilder.csDeletes Expressions-to-IL compiler utility.
src/Java.Interop.Tools.Expressions/Java.Interop.Tools.Expressions/CecilCompilerExpressionVisitor.csDeletes Expressions-to-IL compiler visitor.
src/Java.Interop.Tools.Expressions/Java.Interop.Tools.Expressions.csprojDeletes Expressions project.
src/Java.Interop.Export/Java.Interop/MarshalMemberBuilder.csDeletes Export-side MarshalMemberBuilder implementation.
src/Java.Interop.Export/Java.Interop.Export.csprojDeletes Export assembly project.
samples/Hello-NativeAOTFromJNI/ManagedType.csAdds explicit native registration/marshal method stub instead of post-build generator.
samples/Hello-NativeAOTFromJNI/JavaInteropRuntime.csRemoves UseMarshalMemberBuilder=false usage.
samples/Hello-NativeAOTFromJNI/JavaCallableAttributes.csAdds local attribute definitions for the sample (no Export dependency).
samples/Hello-NativeAOTFromJNI/Hello-NativeAOTFromJNI.targetsRemoves post-build _AddMarshalMethods target.
samples/Hello-NativeAOTFromJNI/Hello-NativeAOTFromJNI.csprojRemoves references to Export + jnimarshalmethod-gen tool projects.
samples/Hello-NativeAOTFromAndroid/JavaInteropRuntime.csRemoves UseMarshalMemberBuilder=false usage.
samples/Hello-NativeAOTFromAndroid/Hello-NativeAOTFromAndroid.targetsRemoves _AddMarshalMethods target and dependency ordering.
samples/Hello-NativeAOTFromAndroid/Hello-NativeAOTFromAndroid.csprojRemoves references to Export + jnimarshalmethod-gen tool projects.
build-tools/automation/templates/core-tests.yamlRemoves CI steps that ran Export tests and marshal-method generator.
MakefileRemoves Export test target and jnimarshalmethod-gen test recipe.
Java.Interop.slnRemoves Export/Expressions/tool projects from the solution.

Comment threadsamples/Hello-NativeAOTFromJNI/ManagedType.cs
Comment threadJava.Interop.sln
@jonathanpeppersjonathanpeppers added the ready-to-review This PR is ready to review/merge, thanks! label Apr 24, 2026

@simonrozsivalsimonrozsival left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

@jonathanpeppers
jonathanpeppers merged commit dedb8f8 into mainApr 27, 2026
6 checks passed
@jonathanpeppers
jonathanpeppers deleted the jonathanpeppers/dev-peppers-remove-jni-marshal-methods branch April 27, 2026 17:20
jonathanpeppers added a commit to dotnet/android that referenced this pull request Apr 27, 2026
…et/java-interop#1405
- Remove UseMarshalMemberBuilder = false from AndroidRuntime and
NativeAOT JavaInteropRuntime (property is now obsolete/no-op).
- Remove deleted Java.Interop.Export and
Xamarin.Android.Tools.JniMarshalMethodGenerator projects from
Xamarin.Android.sln.
- Bump external/Java.Interop submodule to PR 1405 head.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jonathanpeppers added a commit to dotnet/android that referenced this pull request Apr 28, 2026
### Remove UseMarshalMemberBuilder and bump external/Java.Interop to dotnet/java-interop#1405
- Remove UseMarshalMemberBuilder = false from AndroidRuntime and
NativeAOT JavaInteropRuntime (property is now obsolete/no-op).
- Remove deleted Java.Interop.Export and
Xamarin.Android.Tools.JniMarshalMethodGenerator projects from
Xamarin.Android.sln.
- Bump external/Java.Interop submodule to PR 1405 head.
### Copy java-interop.jar to SDK output directory
Add a ProjectReference to Java.Interop.csproj (with
ReferenceOutputAssembly=false) from Xamarin.Android.Build.Tasks.csproj
so that `java-interop.jar` (a Content item in Java.Interop.csproj) gets
copied to the output directory. Previously this happened transitively
through Java.Interop.Export which is now deleted.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
simonrozsival added a commit to dotnet/android that referenced this pull request May 11, 2026
…emap
[JniAddNativeMethodRegistrationAttribute] is a legacy Java.Interop API whose
primary consumer — the jnimarshalmethod-gen build-time generator — was
removed in dotnet/java-interop#1405. The trimmable typemap deliberately does
not support this attribute.
When the scanner detects the attribute on any method, the generator emits
XA4251 telling the developer to either avoid it or switch off the trimmable
typemap (for example, by using the 'llvm-ir' type map implementation) and
report the scenario at https://github.com/dotnet/android/issues. The build
fails via TaskLoggingHelper.HasLoggedErrors.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jonathanpeppers added a commit to dotnet/android that referenced this pull request May 14, 2026
…ith XA4251 (#11274)
### Use trimmable Java proxy runtime sources
Add trimmable-specific java_runtime jars that replace Java.Interop's JavaProxyObject and JavaProxyThrowable sources only for the trimmable typemap path. Keep the existing runtime jars on Java.Interop's native-registration behavior and select the trimmable jars when _AndroidTypeMapImplementation is trimmable.
Re-enable the affected Java.Interop runtime tests and add focused coverage for JavaProxyObject marshaling/object methods under the trimmable typemap path.
### Use trimmable virtual-constructor fixtures
Enable the Java.Interop virtual-constructor tests in the trimmable typemap lane by swapping in Android-owned Java fixtures that use Runtime.registerNatives and generated n_* callbacks instead of ManagedPeer.
Teach the trimmable typemap scanner/model to emit native registrations for hand-written Java peers that opt into JniAddNativeMethodRegistrationAttribute.
### Address Java proxy review comments
Use repository Java formatting for trimmable proxy sources and strengthen the proxy hashCode test so it compares against Java identityHashCode instead of itself.
### Simplify trimmable runtime artifacts
Drop stale _net6 Java runtime artifact names and collapse the trimmable runtime jar/dex to a single shared artifact for CoreCLR and NativeAOT.
### Drop unrelated obsolete-jar cleanup from java-runtime.targets and TrimmableTypeMapBuildTests
This cleanup is not related to fixing InvokeVirtualFromConstructorTests
and belongs in a separate change.
### Refuse [JniAddNativeMethodRegistrationAttribute] in the trimmable typemap
[JniAddNativeMethodRegistrationAttribute] is a legacy Java.Interop API whose
primary consumer — the jnimarshalmethod-gen build-time generator — was
removed in dotnet/java-interop#1405. The trimmable typemap deliberately does
not support this attribute.
When the scanner detects the attribute on any method, the generator emits
XA4251 telling the developer to either avoid it or switch off the trimmable
typemap (for example, by using the 'llvm-ir' type map implementation) and
report the scenario at https://github.com/dotnet/android/issues. The build
fails via TaskLoggingHelper.HasLoggedErrors.
### Move XA4251 reporting into JavaPeerScanner
Address review feedback:
- Drop JavaPeerInfo.HasJniAddNativeMethodRegistrationAttribute. The scanner
now takes an optional ITrimmableTypeMapLogger and reports XA4251 directly
when it encounters the attribute, instead of propagating a bool the rest
of the pipeline doesn't otherwise need.
- Drop the orchestrator's post-scan loop; TrimmableTypeMapGenerator just
passes its logger into JavaPeerScanner.
- Reset external/Java.Interop and external/xamarin-android-tools to the
SHAs on main; this PR doesn't need either submodule moved.
### Restore tests/Mono.Android-Tests/Java.Interop-Tests/java-trimmable/net/dot/jni/test/GetThis.java
This file is unrelated to the XA4251 work; it was accidentally removed during
an earlier 'git rm -r java-trimmable' cleanup. It's still needed by
JavaObjectTest.DisposeAccessesThis under the trimmable typemap.
### Exclude InvokeVirtualFromConstructor fixtures for trimmable
The upstream Java.Interop test fixture CallVirtualFromConstructorDerived
uses [JniAddNativeMethodRegistrationAttribute]. Now that the trimmable
typemap refuses that attribute with XA4251, the offending sources need to
be excluded from the test assembly when building for the trimmable type
map; otherwise the build cannot reach the device tests at all.
Validated locally:
ANDROID_SERIAL=emulator-5554 MSBUILDDISABLENODEREUSE=1 \
./dotnet-local.sh build \
tests/Mono.Android-Tests/Mono.Android-Tests/Mono.Android.NET-Tests.csproj \
-t:RunTestApp -c Release \
-p:_AndroidTypeMapImplementation=trimmable \
-p:UseMonoRuntime=false -nr:false -m:1
TestResult-Mono.Android.NET_Tests-ReleaseCoreCLRTrimmable.xml: 888 total,
0 errors, 0 failures, 21 ignored.
### Detect [JniAddNativeMethodRegistrationAttribute] on non-peer types too
Code-review caught that the prior placement of the XA4251 check sat *after*
the scanner's per-type filtering, so a type carrying the attribute but no
[Register] (and not extending a Java peer) would slip past the diagnostic
and the build would silently succeed.
Hoist the check to immediately after the <Module> skip so it fires uniformly
for every non-<Module> type, regardless of whether the type would otherwise
have been added to the typemap. Add a NonPeerNativeRegistration fixture to
the scanner test to guard the regression.
### Skip per-method XA4251 walk when assembly doesn't reference the attribute
Address Copilot reviewer feedback on the per-type method-attribute walk.
AssemblyIndex.Build now does a cheap pass over the TypeReferences and
TypeDefinitions tables to set MayUseJniAddNativeMethodRegistrationAttribute,
and the scanner short-circuits the per-method walk in the overwhelmingly
common case where the assembly neither imports nor declares the attribute.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Jonathan Peppers <jonathan.peppers@microsoft.com>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators May 28, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

ready-to-reviewThis PR is ready to review/merge, thanks!

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@jonathanpeppers@simonrozsival
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
This repository was archived by the owner on Aug 27, 2026. It is now read-only.

Remove $(AndroidGenerateJniMarshalMethods) support - #1405

Merged
jonathanpeppers merged 5 commits into
mainfrom
jonathanpeppers/dev-peppers-remove-jni-marshal-methods
Apr 27, 2026
Merged

Remove $(AndroidGenerateJniMarshalMethods) support#1405
jonathanpeppers merged 5 commits into
mainfrom
jonathanpeppers/dev-peppers-remove-jni-marshal-methods

Conversation

@jonathanpeppers

Copy link
Copy Markdown
Member

Context: dotnet/android@4296716

Summary

Remove the $(AndroidGenerateJniMarshalMethods) infrastructure from java-interop, which was already removed from dotnet/android.

44 files changed, 54 insertions, 5,513 deletions

What's removed

  • tools/jnimarshalmethod-gen/ — the marshal method generator tool
  • src/Java.Interop.Export/MarshalMemberBuilder implementation + [JavaCallable] attributes
  • tests/Java.Interop.Export-Tests/ — tests for the above
  • src/Java.Interop.Tools.Expressions/ — Expression-to-IL compiler used only by jnimarshalmethod-gen
  • tests/Java.Interop.Tools.Expressions-Tests/ — tests for the above

What's kept (marked [Obsolete])

All public APIs in Java.Interop.dll are retained but obsoleted:

  • CreationOptions.UseMarshalMemberBuilder
  • CreationOptions.MarshalMemberBuilder
  • JniRuntime.MarshalMemberBuilder
  • JniRuntime.JniMarshalMemberBuilder abstract class + all members

Non-abstract methods now throw NotSupportedException.

Runtime simplification

  • JreTypeManager.RegisterNativeMembers — removed the MarshalMemberBuilder fallback path; now throws if TryRegisterNativeMembers fails
  • ManagedValueManager.ActivatePeer — always uses reflection activation
  • MonoRuntimeValueManager.ActivatePeer — uses reflection activation instead of MarshalMemberBuilder.CreateConstructActivationPeerFunc

dotnet/android impact

dotnet/android sets UseMarshalMemberBuilder = false in two places. After this change, those lines should be removed (they'll generate [Obsolete] warnings):

  • src/Mono.Android/Android.Runtime/AndroidRuntime.cs
  • src/Microsoft.Android.Runtime.NativeAOT/Android.Runtime.NativeAOT/JavaInteropRuntime.cs

Build & test

  • Solution builds successfully
  • Java.Interop-Tests: 665 passed, 0 failed
  • JCW-Tests: 47 passed, 0 failed

Delete the jnimarshalmethod-gen tool, Java.Interop.Export library,
Java.Interop.Export-Tests, and Java.Interop.Tools.Expressions projects.
All public APIs in Java.Interop.dll (JniMarshalMemberBuilder,
CreationOptions.UseMarshalMemberBuilder, etc.) are retained but marked
[Obsolete] with no-op implementations.
Runtime code in JreTypeManager, ManagedValueManager, and
MonoRuntimeValueManager is simplified to remove MarshalMemberBuilder
fallback paths.
NativeAOT samples, Makefile, and CI pipeline are updated accordingly.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jonathanpeppers added a commit to dotnet/android that referenced this pull request Apr 16, 2026
Bump \�xternal/Java.Interop\ to dotnet/java-interop#1405, which removes
\Java.Interop.Export\, \jnimarshalmethod-gen\, and
\Java.Interop.Tools.Expressions\.
Changes in dotnet/android:
- Remove \UseMarshalMemberBuilder = false\ from AndroidRuntime and
NativeAOT JavaInteropRuntime (property is now obsolete/no-op).
- Remove deleted \Java.Interop.Export\ and
\Xamarin.Android.Tools.JniMarshalMethodGenerator\ projects from
\Xamarin.Android.sln\.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…eManager trim warnings
- JreTypeManager: Simplify RegisterNativeMembers to return early when
methods is empty (types like JavaProxyThrowable register with no
methods), and throw for non-empty methods without static registration.
- MonoRuntimeValueManager: Add trim suppression attributes for
GetUninitializedObject call to fix NativeAOT publish errors.
- Java.Base-Tests: Add explicit marshal methods and static registration
to MyRunnable and MyIntConsumer test types, since dynamic marshal
method generation via MarshalMemberBuilder is no longer available.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jonathanpeppers
jonathanpeppersforce-pushed the jonathanpeppers/dev-peppers-remove-jni-marshal-methods branch from 01256d8 to 5cb82cdCompareApril 17, 2026 13:51
jonathanpeppersand others added 3 commits April 17, 2026 11:58
…hal methods
ManagedType.cs used [JavaCallable] attributes which relied on the
now-removed jnimarshalmethod-gen tool. Replace with explicit n_*
marshal methods and [JniAddNativeMethodRegistration] static registration.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ration
jcw-gen uses Cecil to find [JavaCallable] and [JavaCallableConstructor]
by attribute name to emit Java-side methods. These attributes must still
exist at compile time for the JCW to include getString() and the
constructor.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
NativeAOT requires delegate types used for JNI callbacks to have
[UnmanagedFunctionPointer] for proper marshalling data generation.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jonathanpeppers added a commit to dotnet/android that referenced this pull request Apr 22, 2026
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jonathanpeppers added a commit to dotnet/android that referenced this pull request Apr 22, 2026
…et/java-interop#1405
- Remove UseMarshalMemberBuilder = false from AndroidRuntime and
NativeAOT JavaInteropRuntime (property is now obsolete/no-op).
- Remove deleted Java.Interop.Export and
Xamarin.Android.Tools.JniMarshalMethodGenerator projects from
Xamarin.Android.sln.
- Bump external/Java.Interop submodule to PR 1405 head.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jonathanpeppers

Copy link
Copy Markdown
MemberAuthor

The dotnet/android test PR looks OK:

There are some flaky tests, but everything builds.

@jonathanpeppers
jonathanpeppers marked this pull request as ready for review April 23, 2026 18:27
CopilotAI review requested due to automatic review settings April 23, 2026 18:27

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR removes the legacy $(AndroidGenerateJniMarshalMethods)-driven marshal-method generation infrastructure from java-interop, aligning with the earlier removal in dotnet/android, while keeping the public surface area in Java.Interop.dll as [Obsolete] stubs that now throw NotSupportedException.

Changes:

  • Removes the jnimarshalmethod-gen tool and the Java.Interop.Export / Java.Interop.Tools.Expressions projects (plus associated tests and pipeline hooks).
  • Simplifies runtime activation/registration paths to rely on reflection and explicit [JniAddNativeMethodRegistration] patterns instead of MarshalMemberBuilder.
  • Updates samples and tests to no longer depend on Java.Interop.Export and generated marshal methods.

Reviewed changes

Copilot reviewed 44 out of 46 changed files in this pull request and generated 2 comments.

Show a summary per file
FileDescription
tools/jnimarshalmethod-gen/Xamarin.Android.Tools.JniMarshalMethodGenerator.csprojDeletes the marshal-method generator tool project.
tools/jnimarshalmethod-gen/TypeMover.csRemoves type-moving logic used by the generator.
tools/jnimarshalmethod-gen/Message.csRemoves generator-specific localized messages.
tools/jnimarshalmethod-gen/App.csRemoves generator app entrypoint and processing pipeline.
tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop/JavaCallableConstructorAttribute.csAdds local test-only attribute type to replace removed Export assembly dependency.
tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop/JavaCallableAttribute.csAdds local test-only attribute type to replace removed Export assembly dependency.
tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop.Tools.JavaCallableWrappers-Tests.csprojStops compiling attribute sources from Java.Interop.Export.
tests/Java.Interop.Tools.Expressions-Tests/Usings.csRemoves global using as the Expressions test project is removed.
tests/Java.Interop.Tools.Expressions-Tests/Java.Interop.Tools.ExpressionsTests/ExpressionAssemblyBuilderTests.csDeletes tests for the removed Expressions toolchain.
tests/Java.Interop.Tools.Expressions-Tests/Java.Interop.Tools.Expressions-Tests.csprojDeletes the Expressions test project.
tests/Java.Interop.Export-Tests/java/net/dot/jni/test/UseJavaCallableExample.javaDeletes Export test Java sources.
tests/Java.Interop.Export-Tests/java/net/dot/jni/test/ExportType.javaDeletes Export test Java sources.
tests/Java.Interop.Export-Tests/Java.Interop/MarshalMemberBuilderTest.csDeletes Export/MarshalMemberBuilder test coverage.
tests/Java.Interop.Export-Tests/Java.Interop/JavaVMFixture.csDeletes fixture used only by Export tests.
tests/Java.Interop.Export-Tests/Java.Interop/JavaCallableExampleTests.csDeletes JavaCallable example tests tied to Export infra.
tests/Java.Interop.Export-Tests/Java.Interop/JavaCallableExample.csDeletes JavaCallable example type tied to Export infra.
tests/Java.Interop.Export-Tests/Java.Interop/ExportTest.csDeletes ExportTest type which relied on MarshalMemberBuilder.
tests/Java.Interop.Export-Tests/Java.Interop.Export-Tests.targetsDeletes MSBuild targets used to build Export test jar and wrappers.
tests/Java.Interop.Export-Tests/Java.Interop.Export-Tests.csprojDeletes Export tests project.
tests/Java.Interop-Tests/Java.Interop/TestType.csStops using MarshalMemberBuilder.CreateMarshalToManagedDelegate(); returns existing delegate directly.
tests/Java.Interop-Tests/Java.Interop/JniRuntimeTest.csRemoves ProxyMarshalMemberBuilder test shim as marshal builder is no longer supported.
tests/Java.Base-Tests/Java.Base/JavaToManagedTests.csAdds explicit native registration methods instead of relying on marshal builder infrastructure.
src/Java.Runtime.Environment/Java.Runtime.Environment.csprojRemoves project reference to Java.Interop.Export.
src/Java.Runtime.Environment/Java.Interop/MonoRuntimeValueManager.csSwitches activation to reflection-based creation instead of CreateConstructActivationPeerFunc().
src/Java.Runtime.Environment/Java.Interop/ManagedValueManager.csRemoves marshal-member-builder activation branch; always uses reflection path.
src/Java.Runtime.Environment/Java.Interop/JreTypeManager.csRemoves marshal-member-builder fallback; now throws if registration isn’t handled explicitly.
src/Java.Interop/Java.Interop/JniRuntime.csRemoves initialization/disposal of marshal member builder.
src/Java.Interop/Java.Interop/JniRuntime.JniMarshalMemberBuilder.csObsoletes marshal member builder APIs; replaces behavior with NotSupportedException.
src/Java.Interop/GlobalSuppressions.csDrops suppression for removed IsDirectMethod analyzer case.
src/Java.Interop.Tools.Expressions/Java.Interop.Tools.Expressions/ExpressionMethodRegistration.csDeletes Expressions helper type.
src/Java.Interop.Tools.Expressions/Java.Interop.Tools.Expressions/ExpressionAssemblyBuilder.csDeletes Expressions-to-IL compiler utility.
src/Java.Interop.Tools.Expressions/Java.Interop.Tools.Expressions/CecilCompilerExpressionVisitor.csDeletes Expressions-to-IL compiler visitor.
src/Java.Interop.Tools.Expressions/Java.Interop.Tools.Expressions.csprojDeletes Expressions project.
src/Java.Interop.Export/Java.Interop/MarshalMemberBuilder.csDeletes Export-side MarshalMemberBuilder implementation.
src/Java.Interop.Export/Java.Interop.Export.csprojDeletes Export assembly project.
samples/Hello-NativeAOTFromJNI/ManagedType.csAdds explicit native registration/marshal method stub instead of post-build generator.
samples/Hello-NativeAOTFromJNI/JavaInteropRuntime.csRemoves UseMarshalMemberBuilder=false usage.
samples/Hello-NativeAOTFromJNI/JavaCallableAttributes.csAdds local attribute definitions for the sample (no Export dependency).
samples/Hello-NativeAOTFromJNI/Hello-NativeAOTFromJNI.targetsRemoves post-build _AddMarshalMethods target.
samples/Hello-NativeAOTFromJNI/Hello-NativeAOTFromJNI.csprojRemoves references to Export + jnimarshalmethod-gen tool projects.
samples/Hello-NativeAOTFromAndroid/JavaInteropRuntime.csRemoves UseMarshalMemberBuilder=false usage.
samples/Hello-NativeAOTFromAndroid/Hello-NativeAOTFromAndroid.targetsRemoves _AddMarshalMethods target and dependency ordering.
samples/Hello-NativeAOTFromAndroid/Hello-NativeAOTFromAndroid.csprojRemoves references to Export + jnimarshalmethod-gen tool projects.
build-tools/automation/templates/core-tests.yamlRemoves CI steps that ran Export tests and marshal-method generator.
MakefileRemoves Export test target and jnimarshalmethod-gen test recipe.
Java.Interop.slnRemoves Export/Expressions/tool projects from the solution.

Comment threadsamples/Hello-NativeAOTFromJNI/ManagedType.cs
Comment threadJava.Interop.sln
@jonathanpeppersjonathanpeppers added the ready-to-review This PR is ready to review/merge, thanks! label Apr 24, 2026

@simonrozsivalsimonrozsival left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

@jonathanpeppers
jonathanpeppers merged commit dedb8f8 into mainApr 27, 2026
6 checks passed
@jonathanpeppers
jonathanpeppers deleted the jonathanpeppers/dev-peppers-remove-jni-marshal-methods branch April 27, 2026 17:20
jonathanpeppers added a commit to dotnet/android that referenced this pull request Apr 27, 2026
…et/java-interop#1405
- Remove UseMarshalMemberBuilder = false from AndroidRuntime and
NativeAOT JavaInteropRuntime (property is now obsolete/no-op).
- Remove deleted Java.Interop.Export and
Xamarin.Android.Tools.JniMarshalMethodGenerator projects from
Xamarin.Android.sln.
- Bump external/Java.Interop submodule to PR 1405 head.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jonathanpeppers added a commit to dotnet/android that referenced this pull request Apr 28, 2026
### Remove UseMarshalMemberBuilder and bump external/Java.Interop to dotnet/java-interop#1405
- Remove UseMarshalMemberBuilder = false from AndroidRuntime and
NativeAOT JavaInteropRuntime (property is now obsolete/no-op).
- Remove deleted Java.Interop.Export and
Xamarin.Android.Tools.JniMarshalMethodGenerator projects from
Xamarin.Android.sln.
- Bump external/Java.Interop submodule to PR 1405 head.
### Copy java-interop.jar to SDK output directory
Add a ProjectReference to Java.Interop.csproj (with
ReferenceOutputAssembly=false) from Xamarin.Android.Build.Tasks.csproj
so that `java-interop.jar` (a Content item in Java.Interop.csproj) gets
copied to the output directory. Previously this happened transitively
through Java.Interop.Export which is now deleted.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
simonrozsival added a commit to dotnet/android that referenced this pull request May 11, 2026
…emap
[JniAddNativeMethodRegistrationAttribute] is a legacy Java.Interop API whose
primary consumer — the jnimarshalmethod-gen build-time generator — was
removed in dotnet/java-interop#1405. The trimmable typemap deliberately does
not support this attribute.
When the scanner detects the attribute on any method, the generator emits
XA4251 telling the developer to either avoid it or switch off the trimmable
typemap (for example, by using the 'llvm-ir' type map implementation) and
report the scenario at https://github.com/dotnet/android/issues. The build
fails via TaskLoggingHelper.HasLoggedErrors.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jonathanpeppers added a commit to dotnet/android that referenced this pull request May 14, 2026
…ith XA4251 (#11274)
### Use trimmable Java proxy runtime sources
Add trimmable-specific java_runtime jars that replace Java.Interop's JavaProxyObject and JavaProxyThrowable sources only for the trimmable typemap path. Keep the existing runtime jars on Java.Interop's native-registration behavior and select the trimmable jars when _AndroidTypeMapImplementation is trimmable.
Re-enable the affected Java.Interop runtime tests and add focused coverage for JavaProxyObject marshaling/object methods under the trimmable typemap path.
### Use trimmable virtual-constructor fixtures
Enable the Java.Interop virtual-constructor tests in the trimmable typemap lane by swapping in Android-owned Java fixtures that use Runtime.registerNatives and generated n_* callbacks instead of ManagedPeer.
Teach the trimmable typemap scanner/model to emit native registrations for hand-written Java peers that opt into JniAddNativeMethodRegistrationAttribute.
### Address Java proxy review comments
Use repository Java formatting for trimmable proxy sources and strengthen the proxy hashCode test so it compares against Java identityHashCode instead of itself.
### Simplify trimmable runtime artifacts
Drop stale _net6 Java runtime artifact names and collapse the trimmable runtime jar/dex to a single shared artifact for CoreCLR and NativeAOT.
### Drop unrelated obsolete-jar cleanup from java-runtime.targets and TrimmableTypeMapBuildTests
This cleanup is not related to fixing InvokeVirtualFromConstructorTests
and belongs in a separate change.
### Refuse [JniAddNativeMethodRegistrationAttribute] in the trimmable typemap
[JniAddNativeMethodRegistrationAttribute] is a legacy Java.Interop API whose
primary consumer — the jnimarshalmethod-gen build-time generator — was
removed in dotnet/java-interop#1405. The trimmable typemap deliberately does
not support this attribute.
When the scanner detects the attribute on any method, the generator emits
XA4251 telling the developer to either avoid it or switch off the trimmable
typemap (for example, by using the 'llvm-ir' type map implementation) and
report the scenario at https://github.com/dotnet/android/issues. The build
fails via TaskLoggingHelper.HasLoggedErrors.
### Move XA4251 reporting into JavaPeerScanner
Address review feedback:
- Drop JavaPeerInfo.HasJniAddNativeMethodRegistrationAttribute. The scanner
now takes an optional ITrimmableTypeMapLogger and reports XA4251 directly
when it encounters the attribute, instead of propagating a bool the rest
of the pipeline doesn't otherwise need.
- Drop the orchestrator's post-scan loop; TrimmableTypeMapGenerator just
passes its logger into JavaPeerScanner.
- Reset external/Java.Interop and external/xamarin-android-tools to the
SHAs on main; this PR doesn't need either submodule moved.
### Restore tests/Mono.Android-Tests/Java.Interop-Tests/java-trimmable/net/dot/jni/test/GetThis.java
This file is unrelated to the XA4251 work; it was accidentally removed during
an earlier 'git rm -r java-trimmable' cleanup. It's still needed by
JavaObjectTest.DisposeAccessesThis under the trimmable typemap.
### Exclude InvokeVirtualFromConstructor fixtures for trimmable
The upstream Java.Interop test fixture CallVirtualFromConstructorDerived
uses [JniAddNativeMethodRegistrationAttribute]. Now that the trimmable
typemap refuses that attribute with XA4251, the offending sources need to
be excluded from the test assembly when building for the trimmable type
map; otherwise the build cannot reach the device tests at all.
Validated locally:
ANDROID_SERIAL=emulator-5554 MSBUILDDISABLENODEREUSE=1 \
./dotnet-local.sh build \
tests/Mono.Android-Tests/Mono.Android-Tests/Mono.Android.NET-Tests.csproj \
-t:RunTestApp -c Release \
-p:_AndroidTypeMapImplementation=trimmable \
-p:UseMonoRuntime=false -nr:false -m:1
TestResult-Mono.Android.NET_Tests-ReleaseCoreCLRTrimmable.xml: 888 total,
0 errors, 0 failures, 21 ignored.
### Detect [JniAddNativeMethodRegistrationAttribute] on non-peer types too
Code-review caught that the prior placement of the XA4251 check sat *after*
the scanner's per-type filtering, so a type carrying the attribute but no
[Register] (and not extending a Java peer) would slip past the diagnostic
and the build would silently succeed.
Hoist the check to immediately after the <Module> skip so it fires uniformly
for every non-<Module> type, regardless of whether the type would otherwise
have been added to the typemap. Add a NonPeerNativeRegistration fixture to
the scanner test to guard the regression.
### Skip per-method XA4251 walk when assembly doesn't reference the attribute
Address Copilot reviewer feedback on the per-type method-attribute walk.
AssemblyIndex.Build now does a cheap pass over the TypeReferences and
TypeDefinitions tables to set MayUseJniAddNativeMethodRegistrationAttribute,
and the scanner short-circuits the per-method walk in the overwhelmingly
common case where the assembly neither imports nor declares the attribute.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Jonathan Peppers <jonathan.peppers@microsoft.com>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators May 28, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

ready-to-reviewThis PR is ready to review/merge, thanks!

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@jonathanpeppers@simonrozsival