Skip to content

Implement Java Bytecode Generator #11922

Closed
Closed

Description

@jonpryor

Context: Issue dotnet/java-interop#524
Context: Issue dotnet/java-interop#534

Allowing JVM-hosted code to invoke managed code requires the use of Java Callable Wrappers for all Java.Lang.Object subclasses. The Java Callable Wrapper contains Java native method declarations for all methods implemented in managed code, e.g. by overriding a virtual method, implementing an interface method, or placing [Java.Interop.ExportAttribute] on a method.

Java Callable Wrappers are currently implemented by using Java source code as an intermediary: JavaCallableWrapperGenerator generates Java source code, which is later compiled by javac to produce Java byte code for later inclusion into an Android application.

We have historically pondered updating Xamarin.Android.Tools.Bytecode to be a read/write API instead of a read-only API, largely for performance reasons: we could avoid the overhead of writing .java files and invoking javac if we just directly emitted a .jar file containing relevant .class files.

We now have another reason to ponder this idea: Full Kotlin support. Kotlin "name mangles" method names in various contexts, emitting Java byte code method names which are not valid Java identifiers:

// Kotlin
package example;

public open abstract class AbstractUnsigned {
	public abstract fun m(value : UInt)
}
// javap example.AbstractUnsigned
public abstract class example.AbstractUnsigned {
  public abstract void m-WZ4Q5Ns(int);
  public example.AbstractUnsigned();
}

Note the example.AbstractUnsigned.m-WZ4Q5Ns() method: it cannot be overridden from Java:

// error: JavaSubclassAbstractUnsigned is not abstract and does not override abstract method m-WZ4Q5Ns(int) in AbstractUnsigned
class JavaSubclassAbstractUnsigned extends example.AbstractUnsigned {
}
class JavaSubclassAbstractUnsigned extends example.AbstractUnsigned {
	public void  m-WZ4Q5Ns(int value) {		
// error: '(' expected
//	public void  m-WZ4Q5Ns(int value) {		
//	              ^
// error: invalid method declaration; return type required
//	public void  m-WZ4Q5Ns(int value) {		
//	               ^
	}
}

So long as we use Java source code as an intermediary, we cannot override or implement Kotlin name-mangled methods.

We could use Kotlin as an intermediate language ("Kotlin Callable Wrappers," anyone?)...

...but why add Kotlin as an intermediate language when we could instead just write Java byte code directly. This would allow the Java Callable Wrapper process to be faster -- no javac invocation would be required -- and means that we avoid any "pesky" issues caused by Kotlin name mangling.

Activity

  1. added theissue type on Apr 29, 2025
  2. removed
    enhancementProposed change to current functionality.
    on Apr 29, 2025
  3. added
    java-interopIssues migrated from dotnet/java-interop / relates to the Java.Interop subtree
    needs-triageIssues that need to be assigned.
    Area: BindingsIssues in Java Library Binding projects.
    on Jul 1, 2026
  4. dotnet-policy-service commented on Jul 1, 2026

    @dotnet-policy-service

    We suspect this issue is stale and no longer relevant. It will be closed if no further activity occurs within 14 more days. Any new comment (by anyone, not necessarily the author) will undo this process.

  5. dotnet-policy-service commented on Jul 15, 2026

    @dotnet-policy-service

    This issue will now be closed since it had been marked "possibly-stale" but received no further activity in the past 14 days. It is still possible to reopen or comment on the issue, but please note that the issue will be locked if it remains inactive for another 30 days.

  6. locked and limited conversation to collaborators on Aug 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Area: BindingsIssues in Java Library Binding projects.java-interopIssues migrated from dotnet/java-interop / relates to the Java.Interop subtreeneeds-triageIssues that need to be assigned.possibly-staleIssues that are potentially no longer relevant.

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions