JvmBridge 26.10.23.4023
dotnet add package JvmBridge --version 26.10.23.4023
NuGet\Install-Package JvmBridge -Version 26.10.23.4023
<PackageReference Include="JvmBridge" Version="26.10.23.4023" />
<PackageVersion Include="JvmBridge" Version="26.10.23.4023" />
<PackageReference Include="JvmBridge" />
paket add JvmBridge --version 26.10.23.4023
#r "nuget: JvmBridge, 26.10.23.4023"
#:package JvmBridge@26.10.23.4023
#addin nuget:?package=JvmBridge&version=26.10.23.4023
#tool nuget:?package=JvmBridge&version=26.10.23.4023
JvmBridge
Write JVM agents in C#. Generate the native bindings. Test the actual binaries.
JvmBridge combines generated JNI/JVMTI declarations, explicit Java reference ownership, and NativeAOT agent entry-point generation in one NuGet package. It works with ordinary Java applications and provides a standalone JVM-hosting API for .NET applications.
JvmBridge is published on NuGet, with companion packages: JvmBridge.Testing for xUnit tests, JvmBridge.Templates for a dotnet new agent template and JvmBridge.Logging for Microsoft.Extensions.Logging adapters. To start without writing a project file, run dotnet new install JvmBridge.Templates, then dotnet new jvmbridge-agent -n MyAgent.
A native agent in a few lines
Create a .NET 10 class library and reference JvmBridge:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<JvmBridgeAgent>true</JvmBridgeAgent>
<PublishAot>true</PublishAot>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="JvmBridge" Version="<version>" />
</ItemGroup>
</Project>
dotnet add package JvmBridge writes this line with the latest version from nuget.org; pin the one you test against. PublishAot is explicit because the SDK decides on NativeAOT while it evaluates the project, before the package's build assets can act on JvmBridgeAgent, so the package cannot imply it. Leaving it out fails the build with JVMB006; without that check dotnet publish would succeed and produce only managed assemblies, and no native library.
using JvmBridge.Agents;
using JvmBridge.Runtime;
public sealed class MyAgent : JavaAgent
{
public override void OnLoad(AgentContext context)
{
context.Log("loaded with options: " + context.Options);
}
public override void OnVmInit(AgentContext context, JavaEnvironment environment)
{
using JavaLocalReference text = environment.NewString("Hello from C#!");
context.Log(environment.GetString(text.Handle));
}
}
No attribute or manually exported entry point is required. The generator finds the single concrete JavaAgent subclass and emits Agent_OnLoad, Agent_OnAttach, and Agent_OnUnload into your assembly. Override Configure to request capabilities before events are installed. OnAttach runs after callbacks are active, so it can immediately retransform existing classes. Abstract agent base classes are allowed; ambiguous or invalid agents produce compiler errors. context.Log writes to standard error without Console, which needs libicu to initialize.
Publish for the JVM process's operating system and architecture:
dotnet publish -c Release -r linux-arm64
java -agentpath:/absolute/path/MyAgent.so=hello -jar application.jar
Windows uses .dll; macOS uses .dylib; Linux uses .so. Native publishing requires the platform's C/C++ toolchain. The resulting library includes its .NET runtime; Java users do not need to install .NET. To load an agent through JAVA_TOOL_OPTIONS or into a running JVM, see Loading and attaching. A Linux agent needs the glibc of the machine that published it or newer; publish against .NET's sysroot for one that loads on glibc 2.17 and later, see Publishing for Linux.
On Unix HotSpot, use the JDK's signal-chaining library when hosting both runtimes in one process. For a typical Linux JDK:
LD_PRELOAD="$JAVA_HOME/lib/libjsig.so" java -agentpath:/absolute/path/MyAgent.so -jar application.jar
Locations differ across distributions and Java versions; Java 8 commonly places the library beneath jre/lib/<architecture>. macOS uses DYLD_INSERT_LIBRARIES with libjsig.dylib. The test runner discovers the correct library. Do not inject HotSpot's library into OpenJ9.
Capabilities
- Generated native API: JNI/JVMTI types, constants, function-table entries, and callback signatures from pinned OpenJDK headers. C# raw declarations live in
JvmBridge.Nativeand preserve native identifiers. - Runtime helpers: JVM creation, thread attachment, UTF-16 string conversion, modified UTF-8 names/options, checked field access, constructor and typed method calls, native registration, and owned local/global references.
- Agent lifecycle: startup and late attachment, VM initialization/death, class preparation, copied JVMTI class/member metadata, capability negotiation, and retransformation.
- Class files and patches: a read-only class-file model with named opcodes and instruction matchers, an editor whose edits keep every constant index and code offset, a writer and code builder for helper classes without byte literals, and declarative
ClassPatches (redirects, constants, replaced constructions, removed fluent calls, added getters, setters and invokers, access flags, matchers, conditions on a method's code andBefore/Aftermethod advice) with results a test can assert on, all without a JVM. - Helper classes: written in Java (
JavaSource, compiled withjavacagainst the application's jars or stub sources, with an optional pinned JDK download for machines that have none) or in C# ([JavaClass]and[JavaMethod]), in the bootstrap loader or the application's own. - Events and JVM state: thread, class-load, exception, method, garbage-collection and monitor events with capability negotiation, thread and stack wrappers, and class redefinition.
- Java interop: arrays, exception throwing, monitors and local frames,
[JavaMethod]with arrays, and typed proxies for the classes of a jar. - Logging and options: levels, a replaceable sink, an
ILoggeradapter and a parsed option string. - Testing:
JvmBridge.Testingsupplies checksum-pinned JDKs and Maven artifacts,javacandjavarunners, published-agent lookup, class-file assertions, disassembly snapshots, patches applied across a jar, and a link check of helpers against real classes. - Delivery and tooling:
-agentpath,JAVA_TOOL_OPTIONS, the Attach API andjava -javaagentwith a jar from thejvmbridgecommand, which also disassembles classes and previews an agent's patches without a JVM. - One package: the runtime, source generator, and MSBuild integration ship together. Consumers do not need Clang or header files.
- Real validation: CI publishes the example against the packed NuGet package and loads it into each available pinned JVM.
Documentation
- User guide: concepts, patching classes, recipes, publishing for Linux, Java 6 and 7, loading and attaching, JVM events, calling between C# and Java, testing, the jvmbridge command, troubleshooting, limitations and stability and versioning.
- Diagnostics: every
JVMBbuild error and what to change. - Compatibility: the generated inventory of JVMs and platforms.
- Footprint: what loading an agent costs in library size, start-up time and memory.
- Contributing: building, testing and maintaining JvmBridge itself.
Compatibility
The manifest tracks every NativeAOT target in scope and every Java major from 8 through 26, with HotSpot and OpenJ9 inventories. Agents also run on Java 6 and 7 from the same build when JavaRelease is 6 or 7; CI runs that on linux-x64 with Zulu 6 and 7, including glibc 2.12 (see Java 6 and 7). Archive availability varies by version and architecture. Mobile targets and platforms without a suitable JVM are explicitly experimental or unavailable.
See the generated compatibility inventory. It shows available downloads, not a blanket support claim. The matching commit's CI reports show which native builds and runtime tests actually passed. Historical patch releases are not exhaustively tested. JVM agent support does not follow automatically from .NET target support.
Examples
- HelloAgent: emits a Java 8-compatible native callback helper in C#, registers native methods, preserves Unicode across threads/global references, transforms fixture method bodies, and supports late attachment.
- LegacyAgent: one build for Java 6 to 26 (
JavaRelease6): a constant patch, a redirect to a C# helper and to a typed Java helper in the application's loader, replaced constructions, a removed fluent call, advice with a hook compiled from Java, events, and a thread attached from .NET. - JavaHost: creates a JVM from an explicit native-library path, invokes Java, handles exceptions, and demonstrates ownership.
See automation setup and agent instructions. Original code is MIT licensed; see upstream notices for header provenance.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- No dependencies.
NuGet packages (2)
Showing the top 2 NuGet packages that depend on JvmBridge:
| Package | Downloads |
|---|---|
|
JvmBridge.Testing
Test helpers for JvmBridge agents on xUnit v3: checksum-pinned JDKs, javac and java runners, published-agent lookup, and class-file assertions. |
|
|
JvmBridge.Logging
Microsoft.Extensions.Logging adapters for JvmBridge agents: an ILogger that writes to the agent's log, and a redirect of the agent's log into an ILogger. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 26.10.23.4023 | 0 | 10/23/2026 |
| 26.10.23.3501 | 0 | 10/23/2026 |
| 26.10.23.2995 | 0 | 10/23/2026 |
| 26.10.23.2515 | 0 | 10/23/2026 |
| 26.10.23.2374 | 0 | 10/23/2026 |
| 26.10.22.7463 | 35 | 10/22/2026 |
| 26.10.22.5110 | 60 | 10/22/2026 |
| 26.10.22.4562 | 56 | 10/22/2026 |
| 26.10.22.4199 | 54 | 10/22/2026 |
| 26.10.22.3403 | 48 | 10/22/2026 |
| 26.10.22.3284 | 48 | 10/22/2026 |
| 26.10.22.2987 | 38 | 10/22/2026 |
| 26.10.22.2593 | 52 | 10/22/2026 |
| 26.10.22.2272 | 67 | 10/22/2026 |
| 26.10.22.2187 | 37 | 10/22/2026 |
| 26.10.22.2063 | 43 | 10/22/2026 |
| 26.10.22.1909 | 40 | 10/22/2026 |
| 26.10.22.1596 | 57 | 10/22/2026 |
| 26.10.22.1508 | 49 | 10/22/2026 |
| 26.10.19.3777 | 105 | 10/19/2026 |
- feat(samples): ✨ used an invoker, conditions and target checks in the legacy agent (8cdc466)
- feat(testing): ✨ pinned Maven artifacts, patched whole jars and link-checked helpers (4b7219c)
- feat(patching): ✨ checked that helpers declare what patches call in them (b38d61f)
- feat(patching): ✨ applied patches on conditions over a method's code (e8beff2)
- feat(patching): ✨ added getters, setters and invokers for private members (8a0ab3c)