Integrating Java* and Microsoft .NET*

by Jon Jagger, Content Master Ltd.


Abstract

The right techniques and practices are key to interoperability of components written in different languages.


Introduction

When building an application, it is increasingly likely that you and your team will have to combine components and/or source code written in different programming languages. It is not uncommon for programmers to spend significant periods of time getting modules written in different languages to interoperate properly. This is one of the key challenges addressed by Microsoft .NET.

It is rarely cost-effective or feasible to manually port or rewrite code from one language into another. Java is a popular language for building applications for Unix*, while Microsoft has developed .NET and the Common Language Runtime (CLR)* for building cross-language applications under Windows*. Java and the CLR use different executable formats, which makes it challenging to build applications that need to integrate existing compiled Java class files into a .NET solution.

Java class files can be integrated into the .NET CLR using the JbImp.exe utility (a command-line tool included in Microsoft Visual J#*). This paper shows how to use to JbImp.exe to convert working sets of Java .class files into .NET executables and .NET assemblies. Readers should note that an alternative way to integrate Java code into .NET is with a Java compiler that outputs .NET Common Intermediate Language (CIL)* code rather than Java byte code (such as the command line compiler vjc.exe, which is also included in Microsoft's J# tool). This technique is covered in a separate white paper titled "Building Portable GUIs."


Definitions

Common Language Runtime (CLR): A fundamental part of the .NET architecture. The CLR manages and runs .NET executables and assemblies in much the same way as the Java Virtual Machine (JVM)* manages and runs the Java byte code inside .class files.

.NET Executable: The .NET equivalent of a classic Win32 EXE file. Unlike Win32 executables, a .NET executable contains CIL instructions and metadata, rather than native code.

.NET Assembly: The .NET equivalent of a classic Win32 DLL file. A .NET assembly also comprises CIL instructions and metadata, rather than native code.

Common Intermediate Language (CIL): The high-level instructions used by the CLR (the CIL equivalent of native machine code). CIL is translated into native code by a just-in-time (JIT) compiler that is part of the CLR. CIL is similar in concept to Java byte code (the instructions used by the JVM) but has better support for value types, and its instructions are mostly typeless.


A Simple Java GUI Application

Listing 1 and Listing 2, below, show parts of a sample Java application to be integrated into .NET.

Listing 1: GuiApplicationLauncher.java

package integrating;

public final class GuiApplicationLauncher {

public static void main(String[] args){

new GuiApplication().init();

}

}

 

Listing 2: GuiApplication.java

package integrating;

import java.awt.*;

import java.awt.event.*;

public final class GuiApplication {

public void init() {

window = newFrame("Java");

//...

window.addWindowListener(newWindowAdapter() {

public void windowClosing(WindowEvent event) {

window.dispose();

System.exit(0);

}});

//...

}

private final static class OnMouseEnteredHandler extends MouseAdapter {

//...

}

private final static class OnMouseExitedHandler extends MouseAdapter {

//...

}

private Frame window;

//...

}

 

If you compile these source files using a native Java compiler, you will create the following .class files:

  • GuiApplication$1.class
  • GuiApplication$OnMouseEnteredHandler.class
  • GuiApplication$OnMouseExitedHandler.class
  • GuiApplication.class
  • GuiApplicationLauncher.class

 

For the purposes of this example, assume that once the code has been compiled and the .class files have been generated, you no longer have access to the original Java source code. Assume further that you have a requirement to execute this code under .NET.


JbImp.exe Working Sets

Before seeing how to use the JbImp.exe tool in various ways, it is important to understand working sets. A working set of files is a collection of files that together form a closed set of dependencies. For example, the first four .class files in the previous list form a minimal working set – they all depend on each other, and none of them depend on GuiApplicationLauncher.class. In contrast, any working set containing GuiApplicationLauncher.class must also contain the other four .class files.

If you specify a set of .class files to JbImp that do not form a working set, then JbImp will issue a diagnostic telling you there are unresolved references.


Using JbImp.exe

You can convert the five .class files into a .NET executable using the JbImp.exe utility. (The default J# installation installs JbImp into the C:Program FilesMicrosoft Visual J# .NETFrameworkBin folder. You need to ensure that this folder is on your PATH.) JbImp reads .class files containing Java byte code and emits .NET CIL with the equivalent functionality. JbImp only supports Java class files based on Java Developer's Kit (JDK)* versions 1.1.4 and earlier (it cannot convert .class files that contain references to Swing*, for example). You can convert the five .class files in this example into a .NET executable with the following command:

jbimp /target:exe /out:FirstDotNetApplication.exe *.class

 

The .exe file created is a self-describing CIL program that is JIT compiled into a native executable by the .NET Virtual Execution System* when run. You can inspect the internal structure of a .NET executable using a tool such as IL DASM (which is supplied with the .NET Framework SDK):

ildasm FirstDotNetApplication.exe

 

Figure 1 shows IL DASM examining the FirstDotNetApplication.exe file:


Figure 1: IL DASM showing the contents of the FirstDotNetApplication.exe file

JbImp preserves the names and types used in the original Java program. The only thing displayed that is not part of the original Java program is the Manifest at the top of the window. The manifest contains the metadata that makes the executable self-describing. You can use IL DASM to inspect the manifest contents (simply double click the word MANIFEST) as shown in Figure 2:


Figure 2. The FirstDotNetApplication manifest

As this figure illustrates, FirstDotNetApplication.exe depends on three other assemblies: mscorlib (containing core .NET functionality), vjscore, and vjslib (Java language and library functionality). These assemblies are supplied with the .NET Framework SDK and Visual J# .NET.

You can also use JbImp to translate working sets of .class files into assemblies. Assemblies are useful because they can be shared and are loaded on demand by the CLR. Any application or assembly running under the CLR can contain references to assemblies created using JbImp, making it feasible, for example, for a C# application to call code that was originally developed and compiled using the JDK. The following command converts four of the five .class files into an assembly (note that you use the /target:library option to create an assembly):

jbimp /target:library /out:DotNetGui.dll GuiApplication.class

GuiApplication$1.class
 GuiApplication$OnMouseEnteredHandler.class

GuiApplication$OnMouseExitedHandler.class

 

JbImp also allows you to combine .NET assemblies and Java .class files into a .NET executable or assembly; use JbImp's /r option to reference the assemblies (make sure the name of the executable is different from the name of any referenced assembly). Notice that assemblies referenced by JbImp do not have to be created using JbImp, which allows an application originally written in Java to make use of c ode written in other languages running under .NET. For example:

jbimp /target:exe /out:SecondDotNetApplication.exe/r:DotNetGui.dll
 GuiApplicationLauncher.class

 

If you inspect this .NET executable using ildasm, you will see a result similar to that shown in Figure 3:

ildasm SecondDotNetApplication.exe

 


Figure 3: IL DASM showing the contents of the SecondDotNetApplication.exe file

Notice that this executable is different from the one shown in Figure 1, in that it does not directly contain the GuiApplication classes. If you inspect its manifest (see Figure 4) you can see that it externally references the DotNetGui assembly. Consequently, SecondDotNetApplication.exe is considerably smaller than FirstDotNetApplication.exe.



Figure 4: The SecondDotNetApplication manifest


C# – Java Interoperability

You have seen how to convert a working set of Java .class files into a .NET assembly and how to share this assembly among one or more .NET executables, as well as how to reference an assembly from another assembly. Because .NET is language-neutral, you can now use this assembly in any .NET project written in any .NET language.

For example, suppose you rewrite GuiApplicationLauncher.java in C# as shown in Listing 3.

Listing 3: GuiApplicationLauncher.cs

namespace CSharp

{

public sealed class GuiApplicationLauncher

; {

public static void Main(string[] args)

{

newintegrated.GuiApplication().init();

}

}

}

 

You can compile this code using the C# command-line compiler and reference the DotNetGui.dll assembly created from the Java .class files:

csc /target:exe /out:ThirdDotNetApplication.exe/r:DotNetGui.dll
 GuiApplicationLauncher.cs

 

Looking at ThirdDotNetApplication.exe with IL DASM (Figure 5) reveals the C# origins of GuiApplicationLauncher.class. For example, notice that Main now starts with an uppercase M:


Figure 5: IL DASM showing the contents of the SecondDotNetApplication.exe file

A final look at the manifest (Figure 6) shows that the Java origin of the DotNetGui assembly is now only visible inside the DotNetGui assembly itself:


Figure 6: The ThirdDotNetApplication manifest


Conclusion

The tools available with the .NET Framework and Visual J# .NET allow you to build applications that integrate code originally created using Java. By converting working sets of .class files into .NET assemblies, you can choose the granularity of integration – it is not an all-or-nothing affair. Once the .class files are converted into .NET assemblies, they can be reused by any .NET program written in any .NET-supported language.


Additional Resources

J#, a Microsoft tool, provides tools to convert Java language source code into CIL (jvc.exe), and Java byte code (.class files) into CIL (jbimp.exe). Microsoft Visual J# is fully integrated with Microsoft Visual Studio 2003*. J# can also be downloaded separately from http://msdn2.microsoft.com/en-us/vjsharp/bb188594.aspx*.

.NET Fra mework SDK contains many tools, including the command line C# compiler (csc.exe), the CIL Disassembler tool (IlDasm.exe), and the .NET Framework libraries. A free download is available at http://msdn2.microsoft.com/en-us/netframework/aa569263.aspx*.

Managed Runtime Environment Developer Center


For more complete information about compiler optimizations, see our Optimization Notice.
Categories: