Skip to content

Commit

Permalink
Merge pull request #75 from NightOwl888/docs/ikvm-wiki
Browse files Browse the repository at this point in the history
Added docs from SourceForge WIKI
  • Loading branch information
wasabii authored Oct 16, 2023
2 parents 629a7e1 + eb9a71e commit 7e019f1
Show file tree
Hide file tree
Showing 18 changed files with 1,217 additions and 0 deletions.
127 changes: 127 additions & 0 deletions docs/class-loader.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
# ClassLoader

The class path or the usage of `ClassLoader`s is a little difficult because Java and .NET are not compatible. When there is an issue, it often results in a [ClassNotFoundException](class-not-found-exception.md).

In Java you can set the class path with:

- the environment variable CLASSPATH
- use the -cp switch on command line
- the property Class-Path in the MANIFEST.MF of a jar file.
- Use a `URLClassLoader` or your own `ClassLoader`

This is a little different in .NET which can produce class loading problems. The following is a list of strategies that can be used to solve class loading problems on .NET.

- [Compile time solutions](#compile-time-solutions)
- [One large assembly](#one-large-assembly)
- [AppDomainAssemblyClassLoader](#appdomainassemblyclassloader)
- [sharedclassloader](#sharedclassloader)
- [ClassPathAssemblyClassLoader](#classpathassemblyclassloader)
- [Runtime solutions](#runtime-solutions)
- [BootClassPathAssemby](#bootclasspathassembly)
- [Context class loader](#context-class-loader)
- [URLClassLoader](#urlclassloader)
- [Related blog entries](#related-blog-entries)

## Compile time solutions

### One large assembly

The simplest solution is to compile all with [ikvmc](tools/ikvmc.md) in a single assembly. There is no class loading problem in this case. The disadvantages are:

- a performance degree, you need to load all possible components. For example all supported JDBC driver if you only need one at one moment.
- duplicate resources files are lost. Like in one jar also in one dll a single file can exist only once. If the resources identical it is no problem. But with service for dynamic loading of components it is fatal. For example a JDBC driver registers it self if it in the classpath. If you have multiple JDBC drivers then only one is registers.

### AppDomainAssemblyClassLoader

This classloader loads from all assemblies that are currently loaded in your application (AppDomain in .NET lingo). So if a referenced assembly has not yet been loaded, it will not be searched at least not by the "AppDomain" part of the class loader, the default assembly class loader mechanism will still load referenced assemblies that are directly referenced by your assembly.

You can set it with the follow command line:

```console
ikvmc -classloader:ikvm.runtime.AppDomainAssemblyClassLoader MyJar.jar
```

### sharedclassloader

If you compile multiple jar files to multiple assemblies then you can use the option sharedclassloader.

```console
ikvmc -sharedclassloader { first.jar } { second.jar } { third.jar }
```
You can only share the classloader between the jar files that was create in one step.

### ClassPathAssemblyClassLoader

It first searches the assembly (and, again, the assembly directly referenced) and then the class path.

```console
ikvmc -classloader:ikvm.runtime.ClassPathAssemblyClassLoader MyJar.jar
```

## Runtime solutions

### BootClassPathAssembly

If you have a Visual Studio project then it does not help if you add the needed dlls as reference. You need also to use it. But an internal, dynamic use with Class.forName(x) can not detect as usage from Visual Studio. If you have a main program written in .NET then you can register your dll with the follow program line at startup of your program.

```c#
ikvm.runtime.Startup.addBootClassPathAssembly(Assembly.Load("YourDll"));
```
The class ikvm.runtime.Startup is saved in IKVM.OpenJDK.Core.dll.

### Context class loader

If you use one of the 3 class loaders for multiple DLL's then this has an effect to the default class loader. But Java know also the concept of the context class loader per thread. The standard class loader use the hierarchical class loader first and then the context class loader.

There are some bad design Java library which only use the context class loader. This look like:

```java
Class.forName( "org.company.abc.DynamicLoadedClass", true, Thread.currentThread().getContextClassLoader() );
```

If you do not set the context class loader then it point to your main assembly and all assembly that are referenced from the compiler. Typical this means you can load all classes from your main assembly, the `BootClassPathAssembly` and from the first Java dll which you call directly.

You can add references to all DLL's in your main assembly with lines like:

```c#
GC.KeepAlive(typeof(org.company.abc.DynamicLoadedClass));
```

This can be difficult if you have a large count of DLLs. Another solution is to set the context class loader to the same as the default class loader before you load the first class.

```c#
java.lang.Class clazz = typeof(org.company.xyz.FirstClass);
java.lang.Thread.currentThread().setContextClassLoader( clazz.getClassLoader() );
new org.company.xyz.FirstClass();
```

### URLClassLoader

Of course, you can also reuse existing class loader classes. Here's an example with `URLClassLoader`:

```java
class MyCustomClassLoader extends java.net.URLClassLoader
{
MyCustomClassLoader(cli.System.Reflection.Assembly asm)
{
super(new java.net.URL[0], new ikvm.runtime.AssemblyClassLoader(asm));
// explicitly calling addURL() is safer than passing it to the super constructor,
// because this class loader instance may be used during the URL construction.
addURL(new java.net.URL("..."));
}
}
```

## Related blog entries

- [Class Loading Architecture](https://web.archive.org/web/20210518052001/https://weblog.ikvm.net/PermaLink.aspx?guid=4e0b7f7c-6f5d-42a3-a4d6-5d05a99c84ff)
- [New Development Snapshot](https://web.archive.org/web/20080502034606/http://weblog.ikvm.net/PermaLink.aspx?guid=8a457a80-1e5f-4182-8f78-b2cd67845553)
- [Writing a Custom Assembly Class Loader](https://web.archive.org/web/20210518035313/http://weblog.ikvm.net/PermaLink.aspx?guid=375f1ff8-912a-4458-9120-f0a8cfb23b68)

## Related

- [ClassNotFoundException](class-not-found-exception.md)
- [Components](components.md)
- [Convert a .jar file to a .dll](convert-a-jar-file-to-a-dll.md)
- [ikvmc](tools/ikvmc.md)
- [Tutorial](tutorial.md)
41 changes: 41 additions & 0 deletions docs/class-not-found-exception.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# ClassNotFoundException

One of the most ask question in the IKVM mailing list is the java.lang.ClassNotFoundException like:

```java
Exception in thread "main" java.lang.ClassNotFoundException: com.xyz.Xyz
at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
at java.security.AccessController.doPrivileged(AccessController.java:279)
at java.security.AccessController.doPrivileged(AccessController.java:520)
at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
at java.lang.ClassLoader.loadClass(ClassLoader.java:450)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
at java.lang.ClassLoader.loadClass(ClassLoader.java:385)
at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:500)
at IKVM.Internal.ClassLoaderWrapper.LoadClassImpl(Unknown Source)
at IKVM.Internal.ClassLoaderWrapper.LoadClassByDottedNameFastImpl(Unknown Source)
at IKVM.Internal.ClassLoaderWrapper.LoadClassByDottedName(Unknown Source)
at IKVM.NativeCode.java.lang.Class.forName0(Unknown Source)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:287)
```

This occurs if you do a mistake at compile time. There can be the following causes:

1. You forgot to compile a needed `.jar` file in an assembly. In this case you should have receive a IKVMC0105 error message from `ikvmc`. Add the missing `.jar` file to your `ikvmc` command line.
2. The different `.dll`s have no references to the other. A simple solution can be to use a [sharedclassloader](class-loader.md#sharedclassloader).
3. Analyze the `ikvmc` warnings to locate the name of the class which was not found.

If this does not help then open a new issue on GitHub. Your issue should include:

- The `ikvmc` command line(s).
- The name of the `.jar` file which include the missing class.
- The name of the `.jar` file which include the class which call `Class.forName`. This can you see in the line under `Class.forName`.
- The warnings from your `ikvmc` call.

## Related

- [ClassLoader](class-loader.md)
- [ikvmc Warnings](tools/ikvmc.md#warnings)
- [Tutorial](tutorial.md)
36 changes: 36 additions & 0 deletions docs/components.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Components of IKVM

## Tools

- [ikvm](tools/ikvm.md)
Starter executable, comparable to java.exe ("dynamic mode"). The Java application will start slow because all classes need to converted on the fly.

- [ikvmc](tools/ikvmc.md)
Static compiler. Used to compile Java classes and jars into a .NET assembly ("static mode"). There are different classloader options.

- [ikvmstub](tools/ikvmstub.md)
A tool that generates stub class files from a .NET assembly, so that Java code can be compiled against .NET code. IKVM understands the stubs and replaces the references to the stubs by references to the actual .NET types.

- IKVM.Runtime.dll
The VM runtime and all supporting code. It contains (among other things):

- Byte Code JIT compiler/verifier: Just-in-time compiles Java Byte Code to CIL.
- Object model remapping infrastructure: Makes System.Object, System.String and System.Exception appear to Java code as java.lang.Object, java.lang.String and java.lang.Throwable.
- Managed .NET re-implementations of the native methods in Classpath.

- IKVM.Java.dll
This are a compiled version of the Java class libraries, plus some additional IKVM specific code.

- ikvm-native.dll / libikvm-native.so
Small unmanaged C library that is used by the JNI interface. This is an optional part, and on Windows it is only required when an application uses it's own native libraries. When running on Linux, this library is also used by the NIO memory mapped files implementation. This library has been designed not to require any changes between IKVM versions, so if you download or compile a new version of IKVM, you don't necessarily need to update this native library.

- IKVM.AWT.WinForms.dll
This are the AWT and Swing peers. This include the java.awt.Toolkit, fonts, images and more GUI stuff.

## Related

- [ClassLoader](class-loader.md)
- [ikvm](tools/ikvm.md)
- [ikvmc](tools/ikvmc.md)
- [ikvmstub](tools/ikvmstub.md)
- [User Guide](user-guide.md)
42 changes: 42 additions & 0 deletions docs/concepts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Concepts

IKVM converts the Java byte-code into .NET IL code (Intermediate Language). This means the result is a .NET application. There are 2 modes for this conversion. On the fly with [ikvm](tools/ikvm.md) and via a compiler with [ikvmc](tools/ikvmc.md).

In both mode you convert byte-code and not the API. IKVM is not a cross-compiler with exceptions. This means you need a Java runtime API in .NET. This are all the dll's of IKVM. This are approximate 40MB overhead for your application. Depending of the used API some not used dll's can be removed if you are finish. This is not recommend.

There are also 2 types of code developments. You can write your code in any Java VM like Java or Scala. Or you write your code in any .NET language like C# or VB#. In the follow we will only speech from Java and C# also if any other language of this platform is possible.

- [Running on the fly](#running-on-the-fly)
- [Running with compiler](#running-with-compiler)
- [Developing in Java code](#developing-in-java-code)
- [Developing in C# code](#developing-in-c-code)

## Running on the fly

In this case you need to develop in Java code (see below). You need only to replace the Oracle or OpenJDK runtime with the IKVM runtime. In some cases it can help to rename ikvm.exe to java.exe. This is how you should begin. This mode is most compatible to Java.

The disadvantages is that this mode is very slow on start time. Every Java byte-code class need to converted to a IL class on every run. This is a large overhead for large projects.

More details can you find in a completely [step by step example](run-a-jar-file-on-the-fly.md).

## Running with compiler

In this mode you compile one or more jar files to a dll or exe file. It is recommended to compile every jar file to a separate dll or exe file. This start many faster than the on the fly mode.

The disadvantage is a switch from the Java class loading concept to the .NET class loading. Several strategies for dealing with the gap between .NET and Java are discussed in the [ClassLoader](class-loader.md) topic.

## Developing in Java code

To access .NET libraries in your Java code you create a stub file from a .NET library. This can you do with [ikvmstub](tools/ikvmstub.md). A IKVM stub file is a *.jar file, a Java library. It contains only definitions of classes and methods, but no code. If you run a stub file with the Oracle Java VM or OpenJDK you will receive an error.

The .NET classes start with the package CLI.

Some .NET constructs require a specific syntax in Java. This are list in [Using .NET with Java](using-dotnet-with-java.md).

## Developing in C# code

This is only possible with compiler mode. You compile you jar files to a dll or exe. Add it as reference to your IDE. You can use every class and method like from any other .NET class library.

Some Java constructs require a specific syntax in .NET. This is exemplified in [Using Java with .NET](using-java-with-dotnet.md).

See the [step by step example](convert-a-jar-file-to-a-dll.md) for details.
106 changes: 106 additions & 0 deletions docs/convert-a-jar-file-to-a-dll.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
# Convert a .jar file to a Class Library (.dll)

This is the recommended solution if you want access a existing Java library from your .NET application. Depending on programming errors in the Java library this can be difficult.

First you need to [download](https://github.com/ikvm-revived/ikvm/releases) and [install](installation.md) IKVM.

## Java sample code

First we create a hello world sample in Java and create a .jar file. The sample Java code of `HelloWorld.java` is very simple:

```java
package hello;

public class HelloWorld {
private String name;

public HelloWorld() {
this.name = "World";
}

public HelloWorld(String name) {
this.name = name;
}

@Override
public String toString() {
return "Hello " + name;
}
}
```

You can save it as `HelloWorld.java` and compile it with the javac command line:

```console
javac HelloWorld.java
```

This should create a file `HelloWorld.class`. With any zip program you can create a .jar file `HelloWorld.jar`. A jar file is only a zip file. The .jar file must include the file `HelloWorld.class` in the folder `hello`. This is the package name of the class. In Java package names are identical to folder names.

## Create a dll

The .jar file compile you with [ikvmc](tools/ikvmc.md). This can you do with the follow command line:

```console
ikvmc -target:library HelloWorld.jar
```

If you want compile more as one .jar file then follow syntax is recommended:

```console
ikvmc -target:library -sharedclassloader { first.jar } { second.jar } { third.jar }
```

Why this is recommend can you read in the [ClassLoader](class-loader.md) topic. This should produce the follow output:

```console
IKVM.NET Compiler version x.x.xxxx.x
Copyright © 2022 Jeroen Frijters, Windward Studios, Jerome Haltom, Shad Storhaug

note IKVMC0002: Output file is "HelloWorld.dll"
```

## C# Sample Code

In your C# IDE you create a new project. Add a reference to `System` and `HelloWorld.dll`. Add a package reference on [IKVM](https://www.nuget.org/packages/IKVM). In your program file you can copy the follow C# sample code:

```c#
using System;
using System.Reflection;

namespace JavaLibrary
{
class Program
{
static void Main(string[] args)
{
//Add references to all jar files that you use not directly
//ikvm.runtime.Startup.addBootClassPathAssemby(Assembly.Load("second"));
//ikvm.runtime.Startup.addBootClassPathAssemby(Assembly.Load("third"));
// set a context classloader, this is not needed for the HelloWorld sample
// but solv problems with some buggy Java libraries
java.lang.Class clazz = typeof(hello.HelloWorld);
java.lang.Thread.currentThread().setContextClassLoader(clazz.getClassLoader());

object obj = new hello.HelloWorld();
Console.WriteLine(obj);
obj = new hello.HelloWorld("Java");
Console.WriteLine(obj);
}
}
}
```

If you run this program then it produce the follow output:

```console
Hello World
Hello Java
```

## Related

- [ClassLoader](class-loader.md)
- [ikvmc](tools/ikvmc.md)
- [Installation](installation.md)
Loading

0 comments on commit 7e019f1

Please sign in to comment.