Java .NET Integration: All Your Options Compared (2026 Guide)

JNBridgePro — the fastest, easiest way to bridge Java and .NET in production. Generate proxies in minutes, call Java from C# (or C# from Java) with native syntax — trusted by enterprises worldwide. Learn more · Download free trial

Table of Contents

If your team needs Java .NET integration, you have more options than ever — but choosing the wrong one can mean months of rework. This guide compares every viable approach to connecting Java and .NET applications, from REST APIs to in-process bridging, with concrete guidance on when to use each.

Need a production-ready solution now? JNBridgePro provides in-process Java/.NET bridging with native method calls — download a free evaluation to test it with your stack.

Whether you’re maintaining legacy Java systems alongside .NET applications, migrating between platforms, or building new hybrid architectures, this comparison will help you make the right architectural decision.

Why Java .NET Integration Matters

Enterprise development teams frequently need Java and .NET to work together. Common scenarios include:

  • Legacy system integration — A .NET front-end needs to access business logic locked in Java libraries
  • Platform migration — Incrementally moving from Java to .NET (or vice versa) without a risky big-bang rewrite
  • Best-of-breed selection — Using Java-only libraries (PDFBox, Tika, Lucene) from .NET applications, or .NET-only libraries from Java
  • Merger and acquisition — Two organizations’ technology stacks must interoperate after a corporate merger
  • BizTalk and JMS — Connecting Microsoft BizTalk Server to Java Message Service (JMS) providers

The right Java .NET interoperability approach depends on your performance requirements, team expertise, and how tightly the two platforms need to be coupled. Let’s examine every option.

The Two Java .NET Integration Architectures

Every Java-.NET integration method falls into one of two categories:

Out-of-Process (Network-Based)

Java and .NET run in separate processes (often on separate machines) and communicate over a network protocol. Examples: REST APIs, gRPC, message queues.

Characteristics: Language-agnostic, easy to scale independently, but adds network latency, serialization overhead, and operational complexity (service discovery, health checks, connection management).

In-Process (Same-Process)

The Java Virtual Machine (JVM) and .NET Common Language Runtime (CLR) run inside the same operating system process. Communication happens through shared memory or native function calls. Examples: JNBridgePro, JNI+P/Invoke, IKVM.

Characteristics: Microsecond-level latency, direct method calls, automatic type marshaling — but requires both runtimes on the same machine.

Most teams default to REST APIs because they’re familiar. But when you need frequent cross-platform calls, tight data coupling, or low latency, in-process integration delivers dramatically better results.

Out-of-Process Approaches

REST APIs / HTTP Services

The most widely used approach: wrap Java functionality in HTTP endpoints (Spring Boot, Jakarta EE, Micronaut) and call them from .NET using HttpClient.

Best for: Loosely coupled microservices where Java and .NET components communicate infrequently (fewer than 10 calls per operation).

Latency per call: 5–50ms depending on payload size and network conditions.

Downsides: Serialization overhead on every call. Error handling becomes distributed systems engineering. You need to maintain API contracts, versioning, and deployment of two separate services.

gRPC with Protocol Buffers

A higher-performance alternative to REST. Uses HTTP/2, binary serialization (Protocol Buffers), and code-generated clients for type-safe cross-service calls.

Best for: Structured cross-service communication with strict typing requirements and moderate call frequency.

Latency per call: 1–10ms — faster than REST due to binary serialization and connection multiplexing.

Downsides: Higher setup complexity (proto file definitions, code generation pipelines). Debugging is harder than REST because payloads aren’t human-readable. Still adds network overhead for every call.

Message Queues (RabbitMQ, Kafka, JMS)

Asynchronous integration where Java and .NET communicate through a message broker. One side publishes messages; the other consumes them.

Best for: Event-driven architectures, batch processing, fire-and-forget workflows where immediate response isn’t needed.

Latency: Milliseconds to seconds depending on broker and consumer configuration.

Downsides: Not suitable for synchronous request-response patterns. Adds infrastructure complexity (broker deployment, monitoring, dead-letter queues). For JMS specifically, JNBridge’s JMS Adapter for BizTalk provides a direct bridge without requiring custom consumer code.

Process.Start (Subprocess Execution)

Launch a Java program as a subprocess from .NET using System.Diagnostics.Process. Communicate via standard input/output or files.

Best for: Infrequent batch operations where a Java CLI tool needs to be triggered from .NET.

Latency: 100ms–2s per invocation (JVM startup cost).

Downsides: Extremely slow. No shared state. Crude error handling. Only viable for very infrequent, isolated tasks.

In-Process Approaches

JNBridgePro — Commercial In-Process Bridge

JNBridgePro runs the JVM and CLR in the same process, generating .NET proxy classes that map directly to Java classes. From C# code, Java objects look and behave like native .NET objects.

// C# code calling Java via JNBridgePro
HashMap map = new HashMap();
map.put("key", "value");
String result = (String) map.get("key");
// No HTTP calls, no serialization — direct in-process method calls

Best for: Enterprise integration requiring frequent cross-platform calls, legacy system access, gradual migration, or any scenario where network overhead is unacceptable.

Latency per call: Microseconds (shared-memory transport).

Key capabilities:

  • Bidirectional calls — Java can call back into .NET code
  • Automatic type marshaling — Java collections ↔ .NET collections
  • Exception propagation with full stack traces
  • Shared-memory and TCP transport options
  • Supports .NET Framework, .NET Core, and .NET 5–9
  • Professional support and comprehensive knowledge base

For a hands-on walkthrough, see our complete guide to calling Java from C#.

JNI + C++ + P/Invoke — Manual Native Bridge

The Java Native Interface (JNI) allows Java to call native (C/C++) code and vice versa. Combined with .NET’s P/Invoke, you can build a bridge: .NET → P/Invoke → C++ → JNI → Java.

Best for: Teams with deep C/C++ expertise who need maximum control over a very narrow integration surface.

Latency per call: Microseconds — comparable to JNBridgePro.

Downsides: Enormous development effort. You’re maintaining code in three languages (C#, C++, Java) plus manual memory management across three runtimes. JNI reference leaks are notoriously difficult to diagnose. Not realistic for broad API surfaces or rapid development.

IKVM — Java Bytecode to .NET CIL Translation

IKVM translates compiled Java bytecode (.class/.jar files) into .NET Common Intermediate Language (CIL) assemblies. The Java code effectively runs on the CLR instead of the JVM.

Best for: Simple, self-contained Java libraries without complex runtime dependencies.

Latency: Native .NET speed (no cross-runtime overhead — the Java code IS .NET code after translation).

Downsides: Doesn’t support all Java APIs. Breaks with libraries that depend on JVM internals, dynamic class loading, or specific JVM behaviors. The project has had periods of dormancy. Cannot run an actual JVM, so Java code that requires a real JVM environment won’t work.

Javonet — Commercial Cross-Runtime Invocation

Javonet is a commercial tool that enables cross-runtime method calls between Java, .NET, Python, Ruby, Perl, and Node.js.

Best for: Polyglot environments where you need integration across more than just Java and .NET.

Latency per call: Low (in-process), though architecture differs from JNBridgePro.

Downsides: Different architecture and licensing model. Worth evaluating alongside JNBridgePro for your specific requirements.

GraalVM Native Image

Compile Java code to a native shared library using GraalVM’s ahead-of-time (AOT) compiler, then load it from .NET via P/Invoke.

Best for: Experimental or greenfield projects where you can accept significant constraints on the Java code.

Latency: Native call speed (no JVM at runtime).

Downsides: Severe restrictions — no dynamic class loading, limited reflection, no Java agents. Requires GraalVM expertise. Not suitable for most existing Java codebases.

jni4net (Deprecated)

An open-source bridge that used JNI under the hood. Last meaningfully updated around 2015. Not recommended for new projects — lacks support for .NET Core/.NET 5+ and has known bugs that will never be fixed.

Full Comparison Table: All Java .NET Integration Methods

MethodTypeLatencySetupMaintenanceJava API CoverageActive Support
REST APIsOut-of-process5–50msMediumMediumFull (service layer)N/A (standard)
gRPCOut-of-process1–10msHighHighFull (service layer)N/A (standard)
Message QueuesOut-of-processms–secondsMediumMediumFull (async only)N/A (standard)
Process.StartOut-of-process100ms–2sLowLowFull (CLI only)N/A (standard)
JNBridgeProIn-processMicrosecondsLowLowFullYes — professional
JNI + P/InvokeIn-processMicrosecondsVery HighVery HighFull (manual)N/A (DIY)
IKVMTranslationNative .NETMediumMediumPartialCommunity
JavonetIn-processLowLowLowFullYes — commercial
GraalVM NativeAOT compiledNativeVery HighHighRestrictedCommunity
jni4netIn-processLowMediumN/A (dead)PartialNo (abandoned)

Java .NET Integration Decision Framework

Use this decision tree to narrow your options:

Do Java and .NET need to run on different machines?

Yes → You need an out-of-process approach. Choose REST for simplicity, gRPC for performance, or message queues for async workflows.

How frequently does .NET call Java (or vice versa)?

  • Rarely (1–10 calls per user request) → REST or gRPC is fine. Network overhead is negligible at low call volumes.
  • Frequently (10–100+ calls per operation) → In-process bridging is essential. Network overhead at this frequency will destroy performance and reliability.

Do you need access to Java class internals (not just service endpoints)?

Yes → You need in-process integration. REST/gRPC only expose what you explicitly wrap in service endpoints. In-process bridges like JNBridgePro give you direct access to any public Java class, method, or field.

Is the Java code a simple, self-contained library?

Yes → IKVM might work. If the library doesn’t depend on JVM internals, dynamic class loading, or complex Java APIs, bytecode translation can be the simplest path.

No → Use JNBridgePro. Complex Java applications with runtime dependencies, dynamic behavior, and broad API surfaces need a real JVM running alongside the CLR.

What’s your team’s C++ expertise?

Strong C++ team → JNI + P/Invoke is technically viable but rarely worth the ongoing maintenance cost.

No C++ expertise → Don’t attempt JNI. The debugging and memory management complexity will consume far more engineering time than any alternative.

Real-World Integration Scenarios

Scenario 1: Accessing a Java PDF Library from .NET

A .NET web application needs to generate and manipulate PDFs using Apache PDFBox (Java). The application processes thousands of documents daily, each requiring multiple PDFBox API calls.

Best approach: JNBridgePro. The high call frequency (dozens of Java method calls per document) makes in-process integration essential. REST wrapping would require serializing document objects on every call. See how JNBridgePro works for the technical architecture.

Scenario 2: BizTalk Server Consuming JMS Messages

A BizTalk orchestration needs to consume messages from an IBM MQ or ActiveMQ JMS queue.

Best approach: JMS Adapter for BizTalk Server. Purpose-built for this exact scenario, with native BizTalk integration and support for all major JMS providers.

Scenario 3: Microservices — Java and .NET Services Communicating

Independent Java and .NET microservices need to exchange data as part of a larger distributed system. Each service owns its own data and business logic.

Best approach: gRPC for synchronous calls, or message queues (Kafka/RabbitMQ) for event-driven communication. Services are intentionally decoupled — in-process integration would defeat the purpose of the microservices architecture.

Scenario 4: Gradual Migration from Java to .NET

An enterprise is incrementally migrating a large Java application to .NET over 18 months. During the transition, the .NET code needs full access to Java business logic that hasn’t been migrated yet.

Best approach: JNBridgePro. The migration period requires tight integration with the existing Java codebase. As components are migrated to .NET, JNBridgePro proxy references are replaced with native .NET code. See how JNBridge customers have handled this.

FAQ

What is the best way to integrate Java and .NET?

The best Java .NET integration approach depends on your requirements. For loosely coupled services communicating infrequently, REST APIs or gRPC work well. For tight integration requiring frequent cross-platform calls, direct library access, or low latency, in-process bridging with JNBridgePro delivers the best balance of performance and maintainability.

Can Java and .NET run in the same process?

Yes. Tools like JNBridgePro run the JVM and .NET CLR in the same operating system process, enabling direct method calls between Java and .NET code with microsecond-level latency and automatic type marshaling. This eliminates the network overhead and serialization costs of out-of-process approaches.

Is IKVM a good alternative to JNBridgePro?

IKVM and JNBridgePro solve different problems. IKVM translates Java bytecode to .NET assemblies — the Java code runs on the CLR, not the JVM. This works for simple libraries but fails with complex Java applications that depend on JVM internals. JNBridgePro runs an actual JVM alongside the CLR, supporting the full Java ecosystem without restrictions.

How much latency does REST add to Java .NET integration?

REST APIs typically add 5–50ms of latency per call, including TCP connection overhead, HTTP request/response framing, and JSON serialization/deserialization. For an operation requiring 50 Java method calls, that’s 250ms–2.5s of pure integration overhead. In-process bridges reduce this to microseconds per call.

What happened to jni4net?

jni4net is an open-source Java-.NET bridge that has been effectively abandoned since approximately 2015. It does not support .NET Core, .NET 5, or any modern .NET version. While it still appears in Stack Overflow answers and blog posts, it is not suitable for new projects. For actively maintained bridging, use JNBridgePro.


Related Articles

Explore Java-.NET integration in depth:

Continue Reading

Call Java from .NET Project: Anatomy of a Shared Memory Bridge

JNBridgePro — the fastest, easiest way to bridge Java and .NET in production. Generate proxies in minutes, call Java from C# (or C# from Java) with native syntax — trusted by enterprises worldwide. Learn more · Download free trial

What We’re Building

In this post we’ll break down the anatomy of a simple interop project where a .NET application calls into a Java class using JNBridgePro with shared memory. If you need to call Java from a .NET project, understanding these moving parts is essential.

The goal is to make the moving parts visible:

  • how a proxy connects the .NET and Java worlds,
  • what files live on each side,
  • other considerations for shared memory setups.

Switching this project to TCP (plus added considerations like SSL, IP/class whitelisting, and Java-side startup) will be covered in a separate post: Changing to TCP: Configuration, SSL, Whitelisting & Startup.

Project Layout for Java .NET Interop

Here’s the directory structure of a demo project (BridgeDemo). At a glance, you can see two main areas:

  • .NET project (BridgeDemo) – the C# application, configuration file, and runtime DLLs.
  • Java side (Java Side) – the original Java class and supporting JARs and properties.

.NET Side: Calling Java with JNBridgePro Shared Memory

On the .NET side, the project is built around referenced assemblies, supporting DLLs, and the App.config that defines how it connects to the Java side.

Referenced Assemblies

  • bridgeDemo.dll – the proxy assembly that exposes the Java class to .NET.
  • JNBShare.dll – the core bridge library required for all JNBridge communication.

Both are added under References in Visual Studio and have Copy Local = True, ensuring they’re automatically placed in the output folder when you build. This way, BridgeDemo.exe can find them at runtime without extra configuration.

Supporting DLLs

  • JNBSharedMem_x86.dll / JNBSharedMem_x64.dll – required only when using the Shared Memory transport.
  • jnbauth_x86.dll / jnbauth_x64.dll – used internally by the bridge for authentication and setup.

These supporting DLLs are not referenced in the project. They simply need to be present in the same directory as BridgeDemo.exe.

App.config

At runtime, BridgeDemo.exe uses this configuration to tell JNBridge how to locate and load the Java side. Below is a sample configuration for the Shared Memory transport:

<jnbridge>
  <dotNetToJavaConfig
    scheme="sharedmem"
    jvm64="C:\Program Files\Java\jdk-25\bin\server\jvm.dll"
    jnbcore="C:\Projects\BridgeDemo\Java Side\jnbcore.jar"
    bcel="C:\Projects\BridgeDemo\Java Side\SharedMemory\bcel-6.10.0.jar"
    classpath="C:\Projects\BridgeDemo\Java Side;C:\Projects\BridgeDemo\Java Side\javaToCall.jar;"
  />
</jnbridge>
  • scheme – transport type (sharedmem or tcp).
  • jvm64 – points to the 64-bit JVM to load (jvm32 used if needed).
  • jnbcore – path to jnbcore.jar, which contains the bridge runtime.
  • bcel – only required when using Shared Memory; omitted for TCP.
  • classpath – tells JNBridge where to find your Java classes or JARs (the Java Side folder in this project).

The classpath section determines whether the .NET side connects to a Java package directory containing .class files, a JAR, or both if listed together. Learn more about how JNBridgePro connects .NET and Java.

Java Side

The Java side hosts the actual code and bridge runtime that the .NET process connects to. It generally includes core/supporting JARs, the Java code or JAR, and a properties file defining how the JVM bridge runs.

Core and Supporting JARs

  • jnbcore.jar – always required; contains the bridge runtime and handles all communication.
  • bcel-6.10.0.jar – only needed for Shared Memory transport.

Java Code or Packaged JAR

You may have either of the following, depending on how your build is structured:

  • A package directory (for example, BridgeDemo/) with .class files.
  • Or a JAR archive (such as BridgeDemo.jar) containing the compiled classes.

Which of these is used depends on the classpath specified in the .NET project’s App.config.

Java-Side Properties File

This file (for example, javaSide.properties) controls how the JVM runs the bridge. Typical entries include:

javaSide.serverType=sharedmem
javaSide.timeout=10000
javaSide.port=8085
javaSide.useClassWhiteList=false
javaSide.classWhiteListFile=./classWhiteList.txt
javaSide.useSSL=false

Considerations for Shared Memory Setups

Shared Memory provides the fastest .NET↔Java communication since both run in the same process, but it requires correct architecture alignment and file placement.

The JVM architecture must match your .NET build target:

  • 64-bit .NET → use 64-bit jvm.dll.
  • 32-bit .NET → use 32-bit jvm.dll. (Note: running x86 shared memory in JNBridgePro v12 may hit a hidden runtime dependency.)

Supporting DLLs must also match:

  • JNBSharedMem_x86.dll / JNBSharedMem_x64.dll
  • jnbauth_x86.dll / jnbauth_x64.dll

You can omit the unused architecture’s DLLs (for example, keep only the x64 set for a 64-bit-only build). If the app may run in both modes (for example, AnyCPU), include all four — JNBridge will automatically load the correct pair at runtime.

All bridge DLLs (JNBShare.dll, JNBSharedMem_x*.dll, jnbauth_x*.dll) must reside in the same directory as your executable.

Handling ClassNotFoundException and NoClassDefFoundError

These errors during shared-memory startup usually come from missing permissions or classloader issues in older JVMs.

  • Permissions – Ensure the user running the app has Read & Execute, List Folder Contents, and Read access to all Java class and JAR folders (jnbcore.jar, bcel-6.x.x.jar, and any app JARs). Missing access prevents the JVM from loading classes, especially under ASP.NET.
  • Classloader conflicts (Java 8 and earlier) – If permissions are correct but errors persist, move the affected .jar from the classpath to the boot classpath using -Xbootclasspath/p: and remove it from the regular classpath.
<jnbridge>
  <dotNetToJavaConfig
    scheme="sharedmem"
    jvm64="C:\Program Files\Java\jdk-25\bin\server\jvm.dll"
    jnbcore="C:\Projects\BridgeDemo\Java Side\jnbcore.jar"
    bcel="C:\Projects\BridgeDemo\Java Side\SharedMemory\bcel-6.10.0.jar"
    classpath="C:\Projects\BridgeDemo\Java Side;"
    jvmOptions.0="-Xbootclasspath/p:C:\Projects\BridgeDemo\Java Side\javaToCall.jar"
  />
</jnbridge>

In this example, javaToCall.jar was removed from the classpath and added to the boot classpath, allowing the JVM to load it earlier and resolve the conflict. (The -Xbootclasspath/p: option works only through Java 8 and was removed in Java 9+.)

Ready to build your own Java .NET interop project? Download JNBridgePro and visit the developer center for more resources.


Related Articles

Related JNBridgePro guides:

JNBridgePro v12 Crash Fix: x86 Shared Memory and Hidden VC++ Runtime Dependency

JNBridgePro — the fastest, easiest way to bridge Java and .NET in production. Generate proxies in minutes, call Java from C# (or C# from Java) with native syntax — trusted by enterprises worldwide. Learn more · Download free trial

Users running JNBridgePro v12 may encounter a crash when using the x86 Shared-Memory transport. This issue does not occur in prior versions or in other configurations, and appears only under very specific circumstances.

Earlier versions of JNBridgePro bundled the Microsoft Visual C++ 2010 Redistributable, which ensured this dependency was present by default. Version 12 no longer includes it, which may cause this issue to appear on clean systems.

The Symptom: x86 Shared Memory Crash

When running unit tests or demo applications using x86 Shared-Memory transport, you may see the following error:

System.AccessViolationException: Attempted to read or write protected memory.

This often happens during early Java proxy calls, such as:

new java.util.HashMap()

The crash occurs only when:

  • The process is compiled for x86
  • Shared-Memory transport is used (see our anatomy of a shared memory project for background)
  • A standard Oracle JRE is installed (e.g. jre1.8.0_202)
  • The v12 version of JNBridgePro is being used

Root Cause: JVM Built with Visual Studio 2010

The issue is caused by a runtime dependency inside the JVM itself, not JNBridgePro.

The 32-bit jvm.dll from many Oracle JRE distributions is built using Visual Studio 2010, which means it dynamically depends on the VC++ 2010 Runtime (msvcr100.dll).

When this runtime is missing, Windows fails to fully load the JVM. But this failure is silent — instead of returning an error, it leads to memory corruption and ultimately causes the System.AccessViolationException.

This affects only Shared-Memory transport because the JVM is loaded directly into the .NET process. Learn more about how JNBridgePro loads the JVM.

How to Confirm the JNBridgePro v12 Crash Cause

To confirm the root cause:

  1. Open Procmon
  2. Add a filter: Path contains msvcr100.dll → Include
  3. Run your x86 Shared-Memory test
  4. If you see events trying to access msvcr100.dll, it confirms the JVM depends on it

You can also use:

dumpbin /dependents path\to\jvm.dll

Or open the file in Dependencies.exe to visually explore the runtime dependency tree.

Solution

Option 1: Use a Different JRE

Switch to a 32-bit JRE that does not depend on the VC++ 2010 runtime — for example, some OpenJDK builds or newer distributions built with later toolchains may avoid this dependency. The 32-bit jvm.dll from Zulu OpenJDK 8 (32-bit) was successfully tested and did not require msvcr100.dll.

Option 2: Install the VC++ 2010 Redistributable (x86)

Installing the Microsoft Visual C++ 2010 Redistributable Package (x86) resolves the issue by providing the required msvcr100.dll used by the JVM.

Final Notes

This is a hidden dependency introduced by the Oracle Java Runtime, not by JNBridgePro. Because the Shared-Memory transport loads the JVM in-process, all of the JVM’s native dependencies must be available at runtime. If any are missing, especially msvcr100.dll, you may see silent failures or memory access violations.

Previous versions of JNBridgePro included the VC++ 2010 Redistributable to prevent this issue. In version 12, it is no longer bundled, so the crash may occur on systems where the runtime is not already installed.

If you’re running into crashes or corruption at startup when using Shared-Memory in x86 mode, this is a likely cause — and easily fixed once identified.

For more troubleshooting help, visit the JNBridge knowledge base or download the latest version.


Related Articles

Related JNBridgePro guides:

JNBridge TCP Configuration: SSL, Whitelisting & Startup Guide

JNBridgePro — the fastest, easiest way to bridge Java and .NET in production. Generate proxies in minutes, call Java from C# (or C# from Java) with native syntax — trusted by enterprises worldwide. Learn more · Download free trial

This post continues from our earlier walkthrough, Anatomy of a .NET Calling Java Project (Shared Memory), and uses the same BridgeDemo project to demonstrate how to change from Shared Memory to JNBridge TCP configuration.

While Shared Memory offers high performance for co-located components, TCP mode is used when the .NET and Java sides run on different machines. When using TCP, you can optionally enable additional features such as SSL encryption, IP whitelisting, and class whitelisting — features that aren’t applicable to Shared Memory connections.

Overview of JNBridgePro TCP Mode

When the bridge runs in TCP mode, the .NET side and the Java side communicate through a socket connection rather than shared memory. This offers several advantages:

  • Cross-platform independence – the .NET and Java components can run on different hosts or operating systems.
  • Remote accessibility – the bridge can connect across LAN or WAN networks.
  • Security options – TCP supports SSL, IP whitelisting, and class-level restrictions (class whitelisting).

Unlike Shared Memory, the Java side must be started first in TCP mode so that the .NET side can connect to it. Learn more about how JNBridgePro works.

Updating the .NET Configuration (App.config) for TCP

In BridgeDemo, open App.config and locate the <dotNetToJavaConfig> section. Change the scheme from sharedmem to jtcp, and specify the host, port, and optional SSL parameters.

  • scheme – must be set to jtcp
  • host – the machine where the Java side is running
  • port – must match the port defined in java.properties

Example:

<jnbridge>
  <dotNetToJavaConfig
    scheme="jtcp"
    host="localhost"
    port="8085"
    useSSL="true"
    clientCertificateLocation=".\testclient.p12"
    clientCertificatePassword="pw"
    sslAlternateServerNames="myServer" />
</jnbridge>

If you are not using SSL, simply omit those attributes or set useSSL to false.

Updating the Java-Side Configuration (java.properties)

On the Java side, update java.properties to switch the bridge to TCP, define the connection port, and enable optional security features like IP and class whitelisting or SSL.

Example — javaSide.properties:

javaSide.serverType=tcp
javaSide.workers=5
javaSide.timeout=10000
javaSide.port=8085
javaSide.useClassWhiteList=true
javaSide.classWhiteListFile=./classWhiteList.txt
dotNetSide.ipWhitelist=127.0.0.1
javaSide.keyStore=./keystore.jks
javaSide.keyStorePassword=changeit
javaSide.trustStore=./cacerts.jks
javaSide.trustStorePassword=changeit

Adding Whitelisting for Java .NET TCP Communication

When using TCP, you can restrict which classes are exposed to .NET and which clients are allowed to connect. These options improve security and control without affecting performance.

Class Whitelisting

Create a file named classWhiteList.txt in the same directory as java.properties. Each line specifies a fully qualified Java class name that can be accessed from the .NET side.

Example — classWhiteList.txt:

bridgeDemo.JavaToCall

Then, enable class whitelisting in java.properties:

javaSide.useClassWhiteList=true
javaSide.classWhiteListFile=./classWhiteList.txt

Only the classes listed here can be loaded by the bridge; all others are blocked automatically.

IP Whitelisting

IP whitelisting limits which machines can connect to the Java bridge. Add the following property to java.properties:

dotNetSide.ipWhitelist=127.0.0.1

Enabling SSL for Secure Java .NET Communication

SSL enables encryption, server authentication, and client authentication, protecting both sides of the bridge and preventing unauthorized access or code execution.

To implement SSL, you must complete all of the steps outlined in the “Secure communications using SSL” section of the JNBridgePro User Guide (p. 78):

  1. Generate and install certificates – Each Java side requires an X.509 server certificate whose Common Name (CN) matches the host where the Java side runs. Each .NET side requires its own client certificate, consisting of a public certificate and a corresponding private-key file.
  2. Create and install the keystore and truststore on the Java side – Install the Java side’s server certificate in a keystore file. Install each authorized .NET side’s client certificate in a truststore file. Both files must have passwords and be referenced in the JavaSide.properties file.
  3. Install certificates on the .NET side – Import the client certificate into the Windows Certificate Store. Leave the public certificate file accessible on disk so it can be referenced in the bridge configuration.
  4. Configure the .NET side for SSL – specify properties in app.config for SSL.

After these steps are completed, all communication between .NET and Java occurs over an encrypted, mutually authenticated SSL channel. The IP and class whitelists, worker-thread pool, and timeout settings continue to apply normally within this secure channel. For more on Java SSL/TLS configuration, see the Oracle JSSE Reference Guide.

Starting the Java Side

The Java side must be started manually before any .NET connections are made. This launches the JNBridge Java component, loads all required classes, and applies the configuration defined in the properties file. Use the following command:

java -cp ".;javaToCall.jar;jnbcore.jar" com.jnbridge.jnbcore.JNBMain /props "javaSide.properties"

This command must be run from the directory that contains the listed JAR files and the javaSide.properties file. When you execute it, Java uses the classpath (-cp) to locate javaToCall.jar (your Java classes) and jnbcore.jar (the JNBridge runtime).

Ready to try TCP mode? Download JNBridgePro and explore the knowledge base for more guides. Need help? Contact us.


Related Articles

Related JNBridgePro guides:

Linux C++ ABI Compatibility: Deploying .so Files to Older Systems

JNBridgePro — the fastest, easiest way to bridge Java and .NET in production. Generate proxies in minutes, call Java from C# (or C# from Java) with native syntax — trusted by enterprises worldwide. Learn more · Download free trial

When deploying shared object (.so) files to Linux-based hardware systems, binaries built on newer Linux distributions may fail at runtime on older systems. This can occur even when CPU architecture and operating system family are the same. Understanding Linux .so compatibility and C++ ABI differences is essential for reliable deployments.

Failures may appear as loader errors, unresolved symbols, or crashes during library initialization.

C++ ABI Compatibility on Linux

On Linux, C++ binaries dynamically link against libstdc++, which provides a defined set of C++ ABI symbols. Newer Linux distributions ship versions of libstdc++ that expose additional ABI symbols (for example, CXXABI_1.3.8).

Older Linux systems may only provide earlier ABI versions, such as CXXABI_1.3.7. If a shared library is built on a system whose libstdc++ exports newer ABI symbols than are available on the target system, the binary may fail to load or execute at runtime.

This mismatch may not be detected during compilation. For more on how the GCC ABI versioning works, see the GCC libstdc++ ABI documentation.

Inspecting ABI Versions on Linux

The ABI symbols provided by libstdc++ on a given system can be inspected using:

strings /usr/lib/x86_64-linux-gnu/libstdc++.so.6 | grep CXXABI_1.3

This output can be used to compare ABI support between build and runtime environments.

Build Environment for Deploying Shared Objects to Older Linux

Shared libraries were rebuilt using an older Linux distribution whose default libstdc++ did not expose newer ABI symbols. The build environment was created using Docker, and Linux binaries were built inside that environment.

SSH Configuration in the Build Environment

When using the older Linux distribution in the build environment, additional steps were required to enable SSH access. A password was first set for the root account, and SSH was configured to allow password-based login. The following changes were made inside the container:

docker exec -it <container-name> bash
passwd
sed -i 's/PasswordAuthentication no/PasswordAuthentication yes/' /etc/ssh/sshd_config
sed -i 's/#PasswordAuthentication yes/PasswordAuthentication yes/' /etc/ssh/sshd_config
sed -i 's/PermitRootLogin without-password/PermitRootLogin yes/' /etc/ssh/sshd_config
sed -i 's/PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config

echo "PasswordAuthentication yes" >> /etc/ssh/sshd_config
echo "PermitRootLogin yes" >> /etc/ssh/sshd_config

mkdir -p /var/run/sshd
service ssh restart

After these steps, SSH access to the container was available.

Building the Shared Libraries

In this container, the .so files were rebuilt and no longer depended on newer ABI symbols.

Summary

  • Linux shared library compatibility can be affected by C++ ABI differences.
  • ABI requirements are determined by the build environment’s libstdc++.
  • Newer Linux systems may introduce ABI symbols not present on older systems.
  • Rebuilding shared libraries in an environment aligned with the target system can resolve runtime compatibility issues.

This case reflects JNBridge’s ongoing work supporting customers with specialized deployment requirements. JNBridgePro enables seamless Java and .NET interoperability, including deployments on Linux. Visit our knowledge base for more technical articles, or download a free trial to get started.


Related Articles

Related JNBridgePro guides:

How to Call C# Code from Java — Complete Guide (2026)

JNBridgePro — the fastest, easiest way to bridge Java and .NET in production. Generate proxies in minutes, call Java from C# (or C# from Java) with native syntax — trusted by enterprises worldwide. Learn more · Download free trial

If you need to call C# from Java, you’re facing one of the most common cross-platform integration challenges in enterprise software development. Whether you need to access a .NET library from a Java application, integrate with a legacy C# system, or bridge teams working across both platforms, this guide covers every viable approach to calling .NET from Java — with working code examples, performance analysis, and clear recommendations.

This is the companion guide to our post on how to call Java from C#. While the concepts are related, calling C# from Java presents unique challenges because Java applications must initiate communication with the .NET Common Language Runtime (CLR), which requires different tooling and techniques.

Can You Call C# Code from Java?

Yes, you can call C# code from Java using several proven methods. The most common approaches include exposing C# functionality through REST APIs, using gRPC for high-performance remote procedure calls, leveraging the Java Native Interface (JNI) with native C++ wrappers, running .NET executables as subprocesses, and using dedicated bridging tools like JNBridgePro that enable direct in-process communication between the Java Virtual Machine (JVM) and the .NET CLR.

The best approach depends on how tightly your Java and C# code needs to be coupled, your performance requirements, and whether you need the .NET code running in the same process as your Java application or as a separate service. Let’s explore each method in depth.

Why Call C# from Java?

Enterprise development teams face this integration challenge in several common scenarios:

  • Accessing .NET-only libraries: Your Java application needs functionality that only exists in a C# or .NET library — a proprietary SDK, a Windows-specific API, or a specialized calculation engine built in .NET.
  • Legacy system integration: Your organization has critical business logic in a C#/.NET codebase that must be consumed by newer Java applications without a full rewrite.
  • Cross-team collaboration: One team develops in Java while another builds in C#, and their systems must share data and functionality in real time.
  • Platform migration: You’re migrating from .NET to Java (or vice versa) and need both systems running simultaneously during the transition period.
  • Best-of-breed architecture: You want to use the strongest libraries from each ecosystem — perhaps a Java-based data pipeline with a .NET-based machine learning model or financial calculation engine.

Understanding your specific use case helps determine which Java-.NET interoperability approach will serve you best.

Overview of All Approaches

When you need to invoke C# from Java, you’re fundamentally connecting two different runtime environments — the JVM (Java Virtual Machine) and the CLR (Common Language Runtime). Each approach handles this connection differently:

  • Network-based approaches (REST, gRPC) keep Java and .NET in separate processes communicating over HTTP or TCP
  • Native interop (JNI + native code) bridges through a compiled C/C++ layer that can load the CLR
  • Subprocess execution runs the .NET application as a separate OS process
  • In-process bridging (JNBridgePro) runs both the JVM and CLR in the same process with automatic proxy generation and type marshaling

Each method involves different trade-offs in latency, development complexity, runtime overhead, and long-term maintenance. The sections below provide code examples and analysis for each approach.

Approach 1: REST APIs and HTTP Services

The most widely discussed method for calling .NET from Java involves wrapping your C# code in HTTP endpoints using ASP.NET Core. Your Java application then sends HTTP requests to the .NET web service and receives JSON responses.

How It Works

  1. Create an ASP.NET Core Web API project exposing your C# functionality as REST endpoints
  2. Deploy the .NET service (IIS, Kestrel, Docker container, etc.)
  3. Use HttpClient or a similar HTTP library in Java to call the endpoints

C# Service (ASP.NET Core):

[ApiController]
[Route("api/[controller]")]
public class CalculationController : ControllerBase
{
    [HttpPost("risk-score")]
    public ActionResult<RiskResult> CalculateRisk([FromBody] RiskInput input)
    {
        var engine = new RiskEngine();
        var result = engine.Calculate(input.Portfolio, input.Parameters);
        return Ok(result);
    }
}

Java Client:

HttpClient client = HttpClient.newHttpClient();
String json = "{\"portfolio\": \"ACME-401K\", \"parameters\": {\"horizon\": 30}}";
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("http://localhost:5000/api/calculation/risk-score"))
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString(json))
    .build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
RiskResult result = objectMapper.readValue(response.body(), RiskResult.class);

Pros

  • Language-agnostic — standard HTTP communication that works between any two technology stacks
  • Well-understood architecture with extensive tooling and documentation
  • Independent scaling and deployment of Java and .NET components
  • Easy to add authentication, rate limiting, and monitoring

Cons

  • Network latency on every call — typically 5–50ms per request, even on localhost
  • JSON serialization and deserialization overhead on both sides
  • Requires deploying and maintaining a separate .NET web service
  • Complex error handling across HTTP boundaries (timeouts, retries, circuit breakers)
  • Not suitable for fine-grained, method-level integration requiring hundreds of calls per operation

REST works best when Java and .NET are genuinely separate services with infrequent, coarse-grained communication. If your Java code needs to call dozens of C# methods per user request, the accumulated network overhead becomes a serious bottleneck.

Approach 2: gRPC with Protocol Buffers

gRPC provides better performance than REST by using binary serialization (Protocol Buffers) and HTTP/2 for transport. It’s a strong choice when you need structured, strongly-typed communication between Java and .NET with better performance than REST.

How It Works

  1. Define your service contract in a .proto file
  2. Generate C# server code and Java client stubs from the contract
  3. Implement the service in C#, call it from Java

Proto Definition:

syntax = "proto3";
service RiskService {
  rpc CalculateRisk (RiskInput) returns (RiskResult);
}
message RiskInput {
  string portfolio_id = 1;
  int32 horizon_days = 2;
}
message RiskResult {
  double score = 1;
  string rating = 2;
}

Java gRPC Client:

ManagedChannel channel = ManagedChannelBuilder.forAddress("localhost", 5000)
    .usePlaintext()
    .build();
RiskServiceGrpc.RiskServiceBlockingStub stub = RiskServiceGrpc.newBlockingStub(channel);
RiskResult result = stub.calculateRisk(
    RiskInput.newBuilder()
        .setPortfolioId("ACME-401K")
        .setHorizonDays(30)
        .build()
);
System.out.println("Risk score: " + result.getScore());

Pros

  • 2–10x faster than REST (binary serialization, HTTP/2 multiplexing, persistent connections)
  • Strongly typed contracts prevent interface drift between Java and .NET teams
  • Built-in streaming support for large data transfers
  • Excellent tooling in both Java and .NET

Cons

  • Still network-bound — latency per call is lower than REST but still measured in milliseconds
  • More complex setup than REST (protoc compilation, code generation pipeline)
  • Contract management overhead — .proto files must stay synchronized
  • Still requires running a separate .NET service process
  • Not suitable for in-process, method-level calls to C# objects

Approach 3: JNI with a Native C++ Bridge

The Java Native Interface (JNI) is a framework built into the JVM that allows Java code to call native C/C++ functions. By writing a native C++ layer that hosts the .NET CLR (using CLR Hosting APIs or COM interop), you can create a bridge from Java through C++ into C#.

How It Works

  1. Write a Java class with native method declarations
  2. Implement the native methods in C++ using JNI
  3. In the C++ code, initialize the .NET CLR and invoke C# methods
  4. Return results back through C++ to Java

Java Side:

public class DotNetBridge {
    static {
        System.loadLibrary("DotNetBridge");
    }
    public native double calculateRiskScore(String portfolioId, int horizonDays);
}

C++ Bridge (simplified):

#include <jni.h>
#include <metahost.h>
#include <mscoree.h>
JNIEXPORT jdouble JNICALL Java_DotNetBridge_calculateRiskScore(JNIEnv *env, jobject obj, jstring portfolioId, jint horizon) {
    // Initialize CLR, load assembly, invoke C# method
    ICLRMetaHost *pMetaHost = NULL;
    CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost, (LPVOID*)&pMetaHost);
    // ... CLR hosting code, method invocation, result extraction ...
    return riskScore;
}

Pros

  • True in-process communication — no network latency
  • Direct access to the CLR from within the JVM process
  • Maximum control over the integration layer

Cons

  • Extreme complexity — requires expertise in Java, C++, and C# plus JNI and CLR hosting APIs
  • Manual memory management across three runtime environments (JVM, native heap, CLR)
  • Platform-specific native code (Windows-only for CLR hosting; Mono/CoreCLR for cross-platform)
  • Extremely difficult debugging — native crashes, memory leaks, and runtime conflicts
  • Every new C# method requires corresponding C++ wrapper code
  • Not viable for most enterprise teams without deep systems programming expertise

JNI is the technically low-level “correct” approach, but the development and maintenance cost is prohibitive for all but the most specialized use cases. Most teams that start down this path eventually abandon it for a higher-level solution.

Approach 4: Running .NET as a Subprocess

The simplest approach: run a .NET console application as a separate process from Java using ProcessBuilder, exchanging data through command-line arguments, standard I/O streams, or files.

ProcessBuilder pb = new ProcessBuilder("dotnet", "run", "--project", "RiskCalculator", "--", "ACME-401K", "30");
pb.redirectErrorStream(true);
Process process = pb.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String result = reader.readLine();
int exitCode = process.waitFor();
System.out.println("Risk score: " + result);

Pros

  • Dead simple to implement — no special libraries or frameworks needed
  • Complete process isolation between Java and .NET
  • Works with any .NET application that has a CLI interface

Cons

  • Massive overhead per invocation — .NET runtime startup costs 100ms–2s per call
  • Data exchange limited to strings (stdout/stdin) or files
  • No shared state between invocations
  • Impractical for frequent or real-time interactions
  • Rudimentary error handling (exit codes and stderr parsing)
  • Security concerns with passing sensitive data via command-line arguments

This approach only makes sense for infrequent, batch-style operations — for example, triggering a .NET report generator from a Java scheduling system once per hour.

Approach 5: In-Process Bridging with JNBridgePro

JNBridgePro takes a fundamentally different approach to Java-.NET interoperability: it runs both the JVM and the .NET CLR in the same process, generating Java proxy classes that let you call C# methods as if they were native Java code. This eliminates network latency, serialization overhead, and the need for complex C++ wrapper code.

How It Works

JNBridgePro’s proxy generation tool analyzes your .NET assemblies (DLL files) and creates corresponding Java classes containing proxy objects. These proxies handle all type marshaling between Java and .NET types automatically — including complex objects, collections, exceptions, and event callbacks.

At runtime, JNBridgePro manages an embedded .NET CLR within your Java process (or vice versa), routing method calls through an optimized shared-memory channel. Both garbage collectors are coordinated to prevent memory leaks and ensure proper object lifecycle management.

Key Capabilities

  • Bidirectional calls: C# code can call back into Java, enabling event-driven and callback-based architectures
  • Automatic type conversion: .NET List<T> ↔ Java ArrayList, Dictionary<K,V>HashMap, and all primitive type mappings
  • Exception propagation: .NET exceptions become Java exceptions with complete stack traces preserved
  • Coordinated garbage collection: No manual memory management — both runtimes’ garbage collectors work together
  • Shared-memory transport: In-process communication with microsecond-level latency
  • Support for modern .NET: Works with .NET Framework 4.x, .NET 6, 7, 8, and 9
  • Support for modern Java: Compatible with Java 8 through Java 21+

For technical details, explore the JNBridgePro Developer Center.

Comparison Table: All C# from Java Integration Methods

ApproachLatency per CallSetup ComplexityMaintenance BurdenIn-Process?Best For
REST APIs5–50msMediumMediumNoLoosely coupled microservices
gRPC1–10msHighHighNoStructured cross-service communication
JNI + C++ + CLR Hosting~MicrosecondsVery HighVery HighYesLow-level systems (expert teams only)
Subprocess (.NET CLI)100ms+ (.NET startup)LowLowNoInfrequent batch tasks
JNBridgePro~MicrosecondsLowLowYesEnterprise integration, frequent calls, production

JNBridgePro delivers in-process performance comparable to JNI but without the complexity of maintaining C++ bridge code, manual cross-runtime memory management, or platform-specific native libraries.

Step-by-Step: Calling C# from Java with JNBridgePro

Here’s a complete walkthrough for using JNBridgePro to call C# methods from Java in a real project.

Step 1: Install JNBridgePro

Download JNBridgePro and install both the Java-side and .NET-side components. The installer includes the proxy generation tool, runtime libraries, and documentation.

Step 2: Generate Java Proxy Classes

Launch the JNBridgePro proxy generation tool and point it at your .NET assemblies (DLL files). The tool analyzes the .NET types and generates corresponding Java proxy classes for each C# class, interface, and enum you want to access.

Step 3: Add Proxies to Your Java Project

Add the generated proxy JAR file and the JNBridgePro runtime JAR to your Java project’s classpath (or Maven/Gradle dependencies).

Step 4: Configure the Runtime

Create a properties file to configure the JNBridgePro runtime:

# jnbcore.properties
dotnet.side=shared-memory
dotnet.assembly.path=./lib/MyDotNetLibrary.dll
dotnet.runtime=coreclr

Step 5: Call C# Methods from Java

With proxies generated, calling C# from Java looks like standard Java code:

import com.jnbridge.jnbcore.DotNetSide;
import MyDotNetLibrary.*; // Generated proxy package

public class Main {
    public static void main(String[] args) {
        // Initialize JNBridgePro runtime
        DotNetSide.init("jnbcore.properties");

        // Create .NET objects and call methods — just like native Java
        RiskEngine engine = new RiskEngine();
        RiskResult result = engine.Calculate("ACME-401K", 30);

        System.out.println("Risk Score: " + result.getScore());
        System.out.println("Rating: " + result.getRating());
        System.out.println("Confidence: " + result.getConfidence());

        // .NET collections work like Java collections
        List<String> factors = result.getRiskFactors();
        for (String factor : factors) {
            System.out.println("Factor: " + factor);
        }
    }
}

No HTTP calls. No serialization code. No C++ wrappers. The .NET RiskEngine object behaves exactly like a native Java object, with full IDE support including code completion, type checking, and debugging.

Performance Considerations

When choosing how to call C# code from Java, performance characteristics vary dramatically across approaches:

Network-based approaches (REST, gRPC) add milliseconds of latency per call. For a business operation requiring 20 C# method calls, you’re accumulating 100ms–1,000ms of pure network overhead — before any actual computation. This compounds under load and introduces failure modes like connection exhaustion, timeouts, and service discovery issues.

Subprocess execution is the slowest option by far. Each invocation pays the full .NET runtime startup cost (100ms–2s), making it viable only for very infrequent operations.

JNI with CLR hosting offers excellent raw performance but carries enormous development risk. Incorrectly managed native references cause memory leaks and crashes that are extremely difficult to diagnose in production environments. Cross-runtime debugging requires specialized tools and deep expertise.

In-process bridging (JNBridgePro) delivers the optimal balance: microsecond-level method call latency with automatic memory management and full type safety. Because both the JVM and CLR share the same OS process, there’s no serialization overhead and no network stack involved — data passes through optimized shared-memory channels.

For applications requiring frequent Java-to-C# interaction (hundreds or thousands of method calls per operation), in-process approaches are the only viable option. Between the two in-process options (JNI and JNBridgePro), JNBridgePro eliminates months of C++ development and ongoing maintenance cost.

What About jni4net, IKVM, and Javonet?

Developers researching how to call C# from Java often encounter several alternative tools in Stack Overflow answers and older blog posts:

jni4net is an open-source library that bridges Java and .NET using JNI. While it appears in many search results and Stack Overflow discussions, the project has been largely unmaintained since 2015. It does not support modern .NET (Core, .NET 5+) and lacks documentation for current Java versions. It can work for simple prototypes on .NET Framework but is not suitable for production enterprise systems.

IKVM translates Java bytecode to .NET CIL, allowing Java code to run on the CLR. This is primarily useful in the opposite direction (running Java code in .NET), and has limitations with complex Java libraries that depend on JVM internals. The project has had periods of dormancy, though community forks exist.

Javonet is a commercial tool that provides cross-runtime method invocation between Java and .NET. It offers a different architecture and licensing model from JNBridgePro and is worth evaluating alongside it for your specific requirements.

GraalVM Native Image allows compiling C# (via .NET’s NativeAOT) or Java into native shared libraries. While technically interesting, it imposes severe restrictions on the source code (limited reflection, no dynamic class loading) and requires significant build pipeline complexity.

JNBridgePro remains the most mature and widely deployed dedicated solution for enterprise Java-.NET interoperability, with active development since 2001, professional technical support, and a comprehensive knowledge base.

When to Use Each Approach

Choose REST APIs when your Java and C# systems are genuinely separate services that communicate infrequently, and you’re already invested in a microservices architecture. This is the most common approach but rarely the best for tight integration.

Choose gRPC when you need better performance than REST with strong contract typing, but your Java and .NET components can operate as independent services with well-defined interfaces.

Choose JNI + C++ + CLR Hosting only if you have a team with deep expertise in C/C++, JNI, and CLR hosting APIs, and you need maximum control over a very narrow, well-defined integration surface. This is rarely the right choice.

Choose subprocess execution for simple, infrequent batch operations where a .NET CLI tool needs to be triggered from a Java scheduler or workflow engine. Avoid for anything requiring low latency or frequent calls.

Choose JNBridgePro when you need:

  • Direct method-level access to C# classes from Java code
  • In-process performance without network overhead or serialization
  • Automatic type marshaling between .NET and Java types
  • Bidirectional communication — Java calling .NET AND .NET calling back into Java
  • Production-grade reliability with professional support and active maintenance
  • Integration with existing .NET libraries or legacy C# systems without modification

For most enterprise scenarios involving Java-.NET interoperability — especially legacy system integration, gradual platform migration, and cross-platform library access — JNBridgePro provides the most productive and reliable path forward.

Ready to evaluate? Download a free trial of JNBridgePro to test with your own codebase, or contact the JNBridge team to discuss your integration requirements.

Frequently Asked Questions

Can Java call C# code directly?

Java cannot call C# code directly because Java runs on the JVM while C# runs on the .NET CLR — two separate runtime environments with different type systems, memory models, and execution engines. However, you can bridge them using network-based approaches (REST APIs, gRPC), native interop (JNI with CLR hosting), or dedicated bridging tools like JNBridgePro that run both runtimes in the same process and handle type conversion automatically.

What is the fastest way to call C# from Java?

The fastest way to call C# from Java is using in-process bridging, which runs the .NET CLR and the JVM within the same application process. This eliminates network latency and serialization overhead entirely, reducing per-call latency to microseconds rather than the milliseconds required by REST or gRPC. Both JNI (with CLR hosting) and JNBridgePro offer in-process performance, but JNBridgePro eliminates the need for C++ wrapper code and manual memory management.

Is jni4net still maintained?

No, jni4net has not been actively maintained since approximately 2015. While it still appears frequently in Stack Overflow answers and search results, it does not support modern .NET versions (.NET Core, .NET 5/6/7/8/9) and is not recommended for new projects. For actively maintained Java-.NET bridging solutions, consider JNBridgePro, which supports current versions of both .NET and Java with professional technical support.

Can you use .NET libraries in a Java application?

Yes, you can use .NET libraries (DLL assemblies) in a Java application. The most practical approaches are: (1) wrapping the .NET library in a REST API or gRPC service that your Java application calls over the network, or (2) using an in-process bridging tool like JNBridgePro that generates Java proxy classes from .NET assemblies, allowing you to call .NET library methods as if they were native Java methods.

How does JNBridgePro handle type conversion between Java and .NET?

JNBridgePro automatically marshals types between the JVM and CLR. Primitive types (int, double, string, boolean) are converted transparently. Complex types are represented as proxy objects — when you access a property or call a method on a proxy, JNBridgePro routes the call to the actual .NET object. Collections like List<T> and Dictionary<K,V> are converted to their Java equivalents (ArrayList, HashMap). Exceptions thrown in .NET are caught and re-thrown as Java exceptions with the original stack trace preserved.

What is the difference between calling C# from Java vs. calling Java from C#?

Both directions of Java-.NET interoperability use similar underlying techniques, but the tooling and setup differ. When calling Java from C#, the .NET application hosts the JVM. When calling C# from Java, the Java application hosts the CLR. JNBridgePro supports both directions with the same licensing and similar proxy generation workflows. For a detailed guide on the reverse direction, see our post on how to call Java from C#.

Does JNBridgePro work with .NET 8 and Java 21?

Yes, JNBridgePro supports modern versions of both platforms, including .NET 8, .NET 9, and Java 21+. It also maintains backward compatibility with .NET Framework 4.x and older Java versions (Java 8+). Check the JNBridgePro product page for the latest compatibility matrix.


Related Articles

Continue exploring Java-.NET integration:

How to Call Java Code from C# — Complete Guide (2026)

JNBridgePro — the fastest, easiest way to bridge Java and .NET in production. Generate proxies in minutes, call Java from C# (or C# from Java) with native syntax — trusted by enterprises worldwide. Learn more · Download free trial

Table of Contents

If you need to call Java from C#, you’re not alone. Enterprise development teams frequently face scenarios where Java and .NET code must work together — whether integrating legacy Java systems, accessing Java-only libraries, or bridging teams that work on different platforms. This guide covers every viable approach to Java-C# interoperability, with code examples, performance analysis, and recommendations for production environments.

Can You Call Java from C#?

Yes, you can call Java from C# using several methods. The most common approaches include REST APIs, gRPC, the Java Native Interface (JNI) through C++ wrappers, running Java as a subprocess, and dedicated bridging tools like JNBridgePro that enable direct in-process communication between the .NET Common Language Runtime (CLR) and the Java Virtual Machine (JVM).

The right approach depends on your performance requirements, how tightly coupled the Java and C# code needs to be, and whether you need the Java code to run in-process or as a separate service. Let’s examine each option in detail.

Overview of Java-C# Interoperability Approaches

When bridging Java and .NET, you’re fundamentally connecting two different runtime environments — the JVM and the CLR. Each approach handles this differently:

  • Network-based approaches (REST, gRPC) keep Java and C# in separate processes and communicate over the network
  • Native interop (JNI + P/Invoke) bridges through native C/C++ code at the system level
  • Subprocess execution (Process.Start) runs Java programs as external commands
  • In-process bridging (JNBridgePro) runs both the JVM and CLR in the same process with automatic type marshaling and proxy class generation

Each has trade-offs in performance, complexity, and maintainability. Understanding these trade-offs is critical for choosing the right architecture for your Java-.NET integration project.

Approach 1: REST APIs and Web Services

The most widely discussed method for calling Java from C# involves wrapping Java functionality in HTTP endpoints. Your C# application sends HTTP requests to a Java web service (typically built with Spring Boot, Jakarta EE, or a similar framework) and receives JSON or XML responses.

How It Works

  1. Package your Java code as a web application with REST endpoints
  2. Deploy the Java service (e.g., on Tomcat or as a Spring Boot JAR)
  3. Use HttpClient in C# to call the Java endpoints

// C# client calling a Java REST service
using var client = new HttpClient();
client.BaseAddress = new Uri("http://localhost:8080");

var response = await client.GetAsync("/api/books?author=Smith");
var books = await response.Content.ReadFromJsonAsync<List<Book>>();

Pros

  • Language-agnostic — works between any two tech stacks
  • Well-understood architecture with abundant tooling
  • Independent deployment and scaling of Java and .NET components

Cons

  • Network latency on every call (typically 5–50ms per request)
  • Serialization and deserialization overhead for every interaction
  • Requires running and maintaining a separate Java web service
  • Complex error handling across network boundaries
  • Not suitable for fine-grained method-level integration

REST APIs work best when Java and C# systems are genuinely separate services with occasional, coarse-grained communication. For tight integration requiring frequent method calls, the overhead becomes prohibitive.

Approach 2: gRPC with Protocol Buffers

gRPC offers better performance than REST by using Protocol Buffers for binary serialization and HTTP/2 for transport. It’s a solid choice when you need structured cross-language communication with strong typing.

How It Works

  1. Define service contracts in .proto files
  2. Generate Java server stubs and C# client stubs from the contract
  3. Implement the service in Java, call it from C#

// book_service.proto
service BookService {
  rpc GetBooks (AuthorRequest) returns (BookList);
}
message AuthorRequest {
  string last_name = 1;
}

// C# gRPC client
var channel = GrpcChannel.ForAddress("http://localhost:5000");
var client = new BookService.BookServiceClient(channel);
var books = await client.GetBooksAsync(new AuthorRequest { LastName = "Smith" });

Pros

  • Faster than REST (binary serialization, HTTP/2 multiplexing)
  • Strongly typed contracts prevent interface drift
  • Streaming support for large data sets
  • Good tooling in both Java and .NET

Cons

  • Still network-bound — latency per call, though lower than REST
  • Contract management overhead (keeping .proto files in sync)
  • More complex setup than REST
  • Not suitable for in-process, method-level Java calls

Approach 3: Java Native Interface (JNI) via C++

The Java Native Interface is a framework built into the JVM that allows native code (C/C++) to interact with Java classes. By combining JNI with .NET’s P/Invoke mechanism, you can build a C++ bridge layer that connects C# to Java.

How It Works

  1. Write C++ functions that use JNI to load the JVM, find Java classes, and invoke methods
  2. Compile the C++ code into a native shared library (.dll / .so)
  3. Use P/Invoke in C# to call the C++ wrapper functions

// C++ JNI wrapper
JNIEXPORT void JNICALL callJavaMethod(JNIEnv *env) {
    jclass cls = env->FindClass("com/example/BookService");
    jmethodID mid = env->GetStaticMethodID(cls, "getBooks", "(Ljava/lang/String;)[Lcom/example/Book;");
    jobjectArray result = (jobjectArray)env->CallStaticObjectMethod(cls, mid, env->NewStringUTF("Smith"));
}

// C# P/Invoke declaration
[DllImport("JavaBridge.dll")]
static extern IntPtr CallJavaMethod(string className, string methodName);

Pros

  • True in-process communication — no network latency
  • Direct access to the JVM from native code
  • Good raw performance once set up

Cons

  • Extreme complexity — requires expertise in C#, C++, and Java
  • Manual memory management across three runtime environments
  • Difficult to debug when things go wrong (native crashes, memory leaks)
  • Platform-specific native code must be maintained per OS
  • No automatic type marshaling — every type conversion is manual
  • Not recommended for teams without deep systems programming experience

JNI is the technically “correct” low-level approach, but the development and maintenance cost makes it impractical for most enterprise teams. The JNI layer in the JVM was designed for extending Java with native code, not for wholesale cross-language integration.

Approach 4: Process.Start — Running Java as a Subprocess

The simplest approach: run a Java program as a separate process from C# using Process.Start, passing data through command-line arguments, standard I/O, or files.


// Launch Java process from C#
var process = new Process
{
    StartInfo = new ProcessStartInfo
    {
        FileName = "java",
        Arguments = "-jar MyJavaApp.jar --author Smith",
        RedirectStandardOutput = true,
        UseShellExecute = false
    }
};
process.Start();
string output = await process.StandardOutput.ReadToEndAsync();
await process.WaitForExitAsync();

Pros

  • Dead simple to implement
  • Complete isolation between Java and C#
  • No additional libraries or frameworks needed

Cons

  • Massive overhead per invocation (JVM startup, process creation)
  • Limited to string-based data exchange
  • No shared state between calls
  • Impractical for frequent or real-time interactions
  • Error handling is rudimentary

This approach only makes sense for infrequent batch-style operations where a Java command-line tool needs to be triggered from a .NET application.

Approach 5: In-Process Bridging with JNBridgePro

JNBridgePro takes a fundamentally different approach: it runs both the JVM and CLR in the same process, generating .NET proxy classes that let you call Java methods as if they were native C# code. This eliminates network latency, serialization overhead, and the need for complex wrapper code.

How It Works

JNBridgePro’s proxy generation tool analyzes your Java classes (from JAR files or classpath) and creates corresponding .NET assemblies containing proxy classes. These proxies handle all type marshaling between .NET and Java types automatically — including complex objects, collections, exceptions, and callbacks.

At runtime, JNBridgePro manages an embedded JVM within your .NET process, routing method calls through an optimized shared-memory channel. Both garbage collectors are coordinated to prevent memory leaks.

Step-by-Step: Calling Java from C# with JNBridgePro {#step-by-step-calling-java-from-c-with-jnbridgepro}

Step 1: Install JNBridgePro

Download JNBridgePro and install both the .NET and Java side components.

Step 2: Generate Proxy Classes

Use the JNBridgePro proxy generation tool to point at your Java JAR files. It creates .NET assemblies containing proxy classes for each Java class you want to access.

Step 3: Configure the Runtime

Add a simple configuration to your .NET application:


using com.jnbridge.jnbcore;

// Initialize the JNBridgePro runtime
DotNetSide.init(".\\jnbcore_tcp.properties");

Step 4: Call Java Methods from C#

With proxies generated, calling Java from C# looks like standard .NET code:


using BookService; // Generated proxy namespace

// Create Java objects and call methods — just like native C#
Author author = new Author("John", "Smith");
Book[] books = Book.getBooks("John", "Smith");

foreach (Book book in books)
{
    Console.WriteLine($"Title: {book.Get_title()}");
    Console.WriteLine($"Publisher: {book.Get_publisher()}");
    Console.WriteLine($"In Stock: {book.Get_inStock()}");
}

No HTTP calls, no serialization code, no C++ wrappers. Java objects behave like .NET objects.

Key Capabilities

  • Bidirectional calls: Java can call back into .NET code, enabling event-driven architectures
  • Automatic collection conversion: Java ArrayList ↔ .NET List, HashMapDictionary
  • Exception propagation: Java exceptions become .NET exceptions with full stack traces
  • Coordinated garbage collection: No manual memory management across runtimes
  • Shared-memory transport: In-process communication with microsecond-level latency

For more details, visit the JNBridgePro Developer Center.

Comparison Table: All Java to C# Integration Methods

ApproachLatency per CallSetup ComplexityMaintenanceIn-Process?Best For
**REST APIs**5–50msMediumMediumNoLoosely coupled microservices
**gRPC**1–10msHighHighNoStructured cross-service communication
**JNI + C++ + P/Invoke**~MicrosecondsVery HighVery HighYesLow-level systems (expert teams only)
**Process.Start**100ms+ (JVM startup)LowLowNoInfrequent batch tasks
**JNBridgePro**~MicrosecondsLowLowYesEnterprise integration, frequent calls, production systems

JNBridgePro delivers in-process performance similar to JNI but without the complexity of maintaining C++ bridge code, manual memory management, or platform-specific native libraries.

Performance Considerations

When choosing how to call Java methods from C#, performance implications vary dramatically:

Network-based approaches (REST, gRPC) add milliseconds of latency per call. For a business operation requiring 10 Java method calls, you’re looking at 50–500ms of pure network overhead. This compounds under load and introduces failure modes (timeouts, connection exhaustion, service discovery issues).

Process.Start is the slowest option. Each invocation pays the full JVM startup cost (typically 100ms–2s), making it viable only for very infrequent calls.

JNI offers excellent raw performance but introduces memory management risks. Incorrectly managed JNI references cause memory leaks that are extremely difficult to diagnose in production. Cross-runtime debugging is also challenging.

In-process bridging (JNBridgePro) provides the best balance: microsecond-level method call latency with automatic memory management and type safety. Because both runtimes share the same process, there’s no serialization or network overhead — data is passed through optimized shared-memory channels.

For applications requiring frequent Java-C# interaction (hundreds or thousands of calls per operation), in-process approaches are the only viable option.

What About jni4net, IKVM, and Javonet?

Developers researching Java-.NET interoperability often encounter several other tools:

jni4net is an open-source library that bridges Java and .NET using JNI under the hood. While it appears in many Stack Overflow answers, the project has been largely unmaintained since 2015 and lacks support for modern .NET (Core/.NET 5+). It can work for simple prototypes but isn’t suitable for production enterprise systems.

IKVM converts Java bytecode to .NET assemblies (CIL). While clever, this approach has significant limitations: it doesn’t support all Java APIs, has compatibility issues with complex Java libraries, and the project has had periods of dormancy. It works best for simple, self-contained Java libraries without complex runtime dependencies.

Javonet is a commercial tool similar to JNBridgePro. It provides cross-runtime method invocation, though with a different architecture and licensing model. Worth evaluating alongside JNBridgePro for your specific requirements.

GraalVM Native Image is a newer approach where Java code is compiled to a native shared library using GraalVM’s ahead-of-time compiler. The .NET application then loads this shared library via P/Invoke. This is technically interesting but imposes severe restrictions on the Java code (no dynamic class loading, limited reflection) and requires significant expertise to set up.

JNBridgePro remains the most mature and widely deployed solution for enterprise Java-.NET integration, with active development, professional support, and a comprehensive knowledge base.

When to Use Each Approach

Choose REST APIs when Java and C# are separate services that communicate infrequently, and you’re already invested in a microservices architecture.

Choose gRPC when you need better performance than REST with strong contract typing, but your Java and C# components can run as separate services.

Choose JNI only if you have a team with deep C/C++ and systems programming expertise, and you need maximum control over a very narrow integration surface.

Choose Process.Start for simple, infrequent batch operations where a Java CLI tool needs to be triggered from .NET.

Choose JNBridgePro when you need:

  • Direct method-level access to Java classes from C#
  • In-process performance without network overhead
  • Automatic type marshaling between .NET and Java types
  • Bidirectional communication (Java calling .NET and vice versa)
  • Production-grade reliability with professional support
  • Integration with legacy Java systems or third-party Java libraries

For most enterprise Java-.NET integration scenarios — especially legacy system integration, gradual migration, and cross-platform library access — JNBridgePro provides the most productive and reliable path forward. Contact JNBridge to discuss your specific integration needs, or download a free trial to evaluate it with your own codebase.

FAQ

Can you call Java from C#?

Yes. You can call Java from C# using REST APIs, gRPC, the Java Native Interface (JNI) with C++ wrappers, subprocess execution, or in-process bridging tools like JNBridgePro. The best approach depends on your performance requirements and how tightly coupled the integration needs to be. For direct method-level calls without network overhead, in-process solutions like JNBridgePro are the most efficient option.

Can .NET be used with Java?

Yes, .NET and Java can interoperate through several mechanisms. Network-based approaches (REST, gRPC) allow .NET and Java applications to communicate as separate services. For tighter integration, bridging tools run both the JVM and CLR in the same process, allowing direct method calls between the two platforms with automatic type conversion.

What is the fastest way to call Java from C#?

The fastest way to call Java from C# is using in-process bridging, which runs the JVM and CLR in the same application process. This eliminates network latency and serialization overhead, reducing per-call latency to microseconds rather than the milliseconds required by REST or gRPC. JNBridgePro and JNI both offer in-process performance, but JNBridgePro does so without requiring C++ wrapper code or manual memory management.

Is jni4net still maintained?

jni4net has not been actively maintained since approximately 2015. While it still appears in many online discussions and Stack Overflow answers, it does not support modern .NET versions (.NET Core, .NET 5/6/7/8/9) and is not recommended for new projects or production systems. For actively maintained Java-.NET bridging, consider JNBridgePro, which supports current versions of both .NET and Java.

What is the Java Native Interface (JNI)?

The Java Native Interface (JNI) is a framework built into the Java Virtual Machine that allows Java code to call and be called by native applications written in C, C++, or other languages. JNI is part of the JDK and is documented in Oracle’s JNI specification. While powerful, using JNI directly for Java-C# integration requires writing C++ wrapper code and managing memory across three runtime environments.

How does JNBridgePro differ from IKVM?

IKVM converts Java bytecode to .NET CIL, essentially translating Java code to run on the CLR natively. JNBridgePro takes a different approach: it runs an actual JVM alongside the CLR in the same process, generating proxy classes that bridge the two. JNBridgePro’s approach supports the full Java ecosystem (including dynamic class loading and all Java APIs), while IKVM has limitations with complex Java libraries and APIs that depend on JVM internals.


Related Articles

Continue exploring Java-.NET integration:

Calling Java from .NET Made Easy with JNBridgePro and Claude Code

JNBridgePro — the fastest, easiest way to bridge Java and .NET in production. Generate proxies in minutes, call Java from C# (or C# from Java) with native syntax — trusted by enterprises worldwide. Learn more · Download free trial

JNBridgePro lets your .NET code call Java classes as if they were native .NET types. But setting up a project from scratch can be daunting — proxy generation, classpath wiring, transport configuration — there are a lot of moving parts to get right.

So we used Claude Code to build a reference project that handles all of that, and then documented the entire thing in a CLAUDE.md file that Claude Code can read. The result: you can point Claude Code at the project, tell it what Java library you want to call from .NET, and it has enough context to walk you through every change.

What’s in the Box

A .NET Framework console app that calls Java’s log4j logging library and a custom Java class through JNBridge-generated proxy DLLs. The project is organized into three folders — Java source, proxy generation tooling, and the .NET project — with orchestrator scripts that build and run everything in one step.

The CLAUDE.md documents every file, every build step, and every configuration flag. This means Claude Code understands the full project structure — when you ask it to swap in a different Java library or change the transport mode, it knows exactly which files to touch and why.

Two Ways to Run: Shared Memory vs. TCP

The demo ships with two build scripts, each demonstrating a different JNBridge transport mode.

buildAndRunSharedMem.bat — Shared Memory Mode

This embeds the JVM directly inside the .NET process. No separate Java process to manage.

  1. Compiles Java source and packages it into a JAR
  2. Generates .NET proxy DLLs — JNBridge scans your JARs and creates C# wrapper classes for each Java class you want to call
  3. Builds the C# project with dotnet build
  4. Generates the runtime config — injects your JVM paths from env.bat into the output config file
  5. Runs the demo

buildAndRunTCP.bat — TCP Mode

This runs Java as a separate process and connects over TCP (port 8085). Useful for debugging the Java side independently or running Java on a different machine.

  1. Compiles Java and generates proxies (same as above)
  2. Builds the C# project
  3. Swaps in the TCP config instead of the shared-memory config
  4. Launches the Java side in a separate console window
  5. Runs the .NET app, which connects to the Java side over TCP
  6. Cleans up the Java process when the demo exits

Getting Started with JNBridgePro

1. Install JNBridgePro and Download Demo

Download JNBridgePro v12.0 from jnbridge.com and run the installer.

Download Demo with claude.md

2. Request a License

After installation, run the JNBridge registration tool to request a license. Go to Registration Key → copy registration key → select “request license” to complete the online license request. We’ll email you a license.

Then, add the license to the build directory or JNBridge install directory.

3. Edit env.bat

This is the only file you need to customize. Open env.bat at the project root and set JAVA_HOME to point to your Java 8 JDK:

set JAVA_HOME=C:\Program Files\Java\jdk1.8.0_202

That’s it. All the build scripts read their Java paths from this one file.

4. Run It

Double-click buildAndRunSharedMem.bat. If everything is set up correctly, you’ll see .NET calling Java.

Adapting It with Claude Code

This is where the CLAUDE.md pays off. Open Claude Code in the project directory and tell it what you want — “swap log4j for my JDBC driver,” “add a new Java class to the proxies,” “switch to TCP mode.” Claude Code reads the documentation and knows the full build pipeline, so it can make the right changes across all the files without you having to trace through the wiring yourself.

Ready to try it? Download JNBridgePro and the Demo to get started. Or check out the Developer Center for more guides and documentation.


Related Articles

Learn more about JNBridgePro:

Announcing JNBridgePro 7.0

Today we’re excited to announce JNBridgePro 7.0, with two new major features: support for Mono, and the elimination of “bitness” issues. These improvements will enable users to expand the reach of their applications, and simplify the development and deployment process.

JNBridgePro 7.0 can now run on Mono

One of the most common questions about JNBridgePro that we’ve had to say no to is “Can it run on Mono?” Starting today with JNBridgePro 7.0, the answer is yes. As a user of JNBridgePro, you’ve created applications that combine .NET and Java code, where the .NET code runs on Windows machines, and the Java code runs in a JVM. Now with JNBridgePro 7.0, the .NET code can also run on Linux machines, using the Mono runtime. (As always, the Java sides of the applications can run on any platform that can run Java.)

Why use Mono? Here are four examples:

  1. You want to move your existing .NET & Java application onto a commodity Linux server for business or technical reasons.
  2. You want to create greenfield applications on Linux platforms. In this example, you can build an application that combines an ASP.NET Web application with Java EE code running on an application server, and have the entire result run on a Linux server.
  3. You want to move your .NET & Java application to a Linux-based IaaS cloud provider.
  4. As an ISV, you want to expand your.NET&Java application’s footprint beyond Windows to support for Linux:

No code changes are necessary to move your .NET & Java applications that use JNBridgePro from Windows to Linux, just some possible configuration file changes, so your existing applications will just work.

JNBridgePro 7.0’s current Mono support is on Linux, on the Ubuntu, openSUSE, and Debian distributions currently supported by Mono, as well as on Windows. We’re considering extending JNBridgePro’s Mono support to additional platforms, based on customer feedback. JNBridgePro will work on Mono in both the .NET-to-Java and Java-to-.NET directions using the TCP/binary communications mechanism, and in the .NET-to-Java direction using the HTTP/SOAP communications mechanism. Future releases will fill in the gaps in available communications mechanisms, so you will be able to use any mechanism on any platform.

Microsoft .NET
(Windows)
Mono
(Linux, Windows)
.NET-to-JavaShared memoryTCP/binary

HTTP/SOAP

TCP/binaryHTTP/SOAP
Java-to-.NETShared memoryTCP/binary

HTTP/SOAP

TCP/binary

Unified 32-bit and 64-bit

Ever since we’ve introduced support for 64-bit platforms, customers have sometimes been confused by “bitness” issues. In JNBridgePro 7.0, we’ve eliminated bitness-related confusion by unifying our 32-bit and 64-bit distributions into a single release.

First, customers no longer need to decide ahead of time whether they need 32-bit or 64-bit JNBridgePro – now, there’s just a single installer containing the components and tools that will work for you regardless of whether you’re creating 32-bit or 64-bit applications. That means that there will be no more situations where you first download the 64-bit JNBridgePro installer, then need to go back and download the 32-bit version.

Second, you can now create “Any CPU” applications that work with the shared-memory communications mechanism. “Any CPU” applications will run as 64-bit processes on 64-bit systems, and as 32-bit processes on 32-bit systems. Since the JNBridgePro shared-memory components contain native code and come in 32-bit and 64-bit flavors, there used to be situations where users would create an “Any CPU” application using shared memory that ran fine on a 64-bit machine, but that threw an exception on a 32-bit machine (or vice versa). In such cases, the user would have to go back and create separate 32-bit and 64-bit builds using the proper shared memory components. Now, you can create a single “Any CPU” build that contains both the 32-bit and 64-bit shared memory components, and the correct ones will be used depending on the bitness of the currently-running process. This increases flexibility in deployment, speeds up the time spend building and testing, and eliminates potential errors.

Download the new version

JNBridgePro 7.0, with Mono support and unified 32/64-bit capabilities, is available for download now. Download it here, or check out the documentation and our demos and examples.

Java-in-.NET embedding and Java 7 and 8

Embedding Java components in .NET applications, when using Java 7 or 8, doesn’t work the same way it previously did with Java 5 or 6, as the focus handling has changed.

When Java components are embedded in .NET applications, and Java 7 or 8 is being used, focus-related events like keyboard events and mouse wheel events are no longer handled properly — they are no longer directed to the appropriate component, but rather are directed to the wrong place and dropped. (Other mouse events, including clicks, which are not focus-related, still function properly.)

Starting with Java 7, the Windows implementation of the AWT focus subsystem was changed.  Previously, every AWT and Swing component was mapped to an underlying Windows component (a “focus proxy”) that handled focus-related events and dispatched them to the appropriate AWT/Swing component. With Java 7 (and continuing into Java 8), the owning frame acts as the focus proxy for all components that are contained within it. Oracle claims that “the mechanism is transparent for a user,” but the change does dramatically affect the behavior of Java AWT and Swing components that are embedded inside Windows Forms and WPF applications. Our research indicates that the AWT focus subsystem is choosing the wrong Windows component as the focus proxy.

We are currently working on a fix to this problem, but we have no estimate on when that fix will be ready. In the meantime, if you are embedding Java components in .NET applications, we recommend using Java 6 for the moment. Note that if your embedded Java component does not depend on focus-related events (for example, it does not take text input or use keyboard shortcuts or respond to mouse wheel events), then you should be able to use Java 7 or 8.

Also note that embedding .NET UI components inside Java applications still works fine as before, whether Java 5, 6, 7, or 8 is being used.

We thank you for your patience while we work on this issue, and we apologize for the inconvenience.