kagamihogeの日記

kagamihogeの日記です。

JNBridge さわってみた

宣伝文句によると「Java -> .NET .NET -> Java ができるようになるブリッジ」とかなんとか。JNBridgePro 4.0 が Visual Studio と Eclipse 用のプラグインを新たに導入 によると中々勇ましいことが書いてあるのだが、はてさて。今回はマニュアルとサンプル見ながら Java -> .NET を試してみました。

使用するもの

.NET と Java をブリッジする class ファイルの生成

DL したインストーラを起動してデフォルトのままインストールを終える。完了するとデスクトップに JNBProxy v4.0 (.NET 1.x-targeted) と JNBProxy v4.0 (.NET 2.0-targeted) の 2 アイコンが出来る。今回は .NET 2.0 使うので後者を起動する。

起動すると、既存プロジェクト使うか、Create new .Net -> Java project か Create new Java -> .NET project か聞かれる。今回は Java -> .NET やりたいんで Create new Java -> .NET project を選択。

Project -> Java Options を選ぶ。初回起動時はこの画面出てきたっけな? 画面の左側は Java -> .NET 通信方式の選択。それぞれの特徴は公式ページから抜粋。

 * On the same machine in the same process via shared memory,
 * On the same machine in different processes via socket communications,
 * Over any network via a fast binary protocol,
 * Or over the Internet via HTTP/SOAP. 
 
 http://www.jnbridge.com/jnbpro.htm より

常識的に考えれば .NETJava も同一マシン上で動かすなら Shared memory がよさげな予感。でも Shared memory 選ぶとダイアログが出て注意される。

We do not recommend using shared memory communications with the GUI version of the proxy generation tool, since you will need to exit and restart the tool every time you change the classpath.

後半はともかく、前半は「素人にはおすすめできない」的なことが書いてある。なので Binary/TCP を選択。java.exe のパス設定を求められるので設定する。ウチは 1.5.0_15 の SDK のを使いました。jnbcore.jar と bcel.jar は自動設定されたと思うけど、一応デフォルト設定をメモ。それぞれ C:\Program Files\JNBridge\JNBridgePro v4.0\jnbcore\jnbcore.jar と C:\Program Files\JNBridge\JNBridgePro v4.0\jnbcore\bcel-5.1-jnbridge.jar になる。jdk1.5 使うので Generate J2SE 5.0-targeted proxies にもチェックを入れておく。入れてない場合に動くかどうかは試してない。

次に Project -> Edit Assembly List を選択。C:\WINDOWS\assembly にあるグローバル・アセンブリ・キャッシュ(GAC)を使う場合は Add from GAC... を押して適当に追加する。

今回は、テキトーな独自の .NET C# アセンブリ作る。Visual Studio 2008 はあまり良く知らないので手順割愛。

using System;
using System.Collections.Generic;
using System.Text;

namespace HogeHoge2
{
    public class Class1
    {
        public int getAddAnswer(int a, int b)
        {
            return a + b;
        }
    }
}

作成した dll は説明簡易化のため C:\HogeHoge2.dll に移動。

再び Edit Assembly List に戻る。Add... を押して C:\HogeHoge2.dll を選択して OK を押す。この段階では画面は特に変化なし。

次に Project -> Add Classes from Assembly List ... を選択する。Enter class name here: に HogeHoge2.Class1 を入れる。GAC のクラスを使う場合は別途該当ドキュメントを参照して正しいクラス名入れてください。ちなみに dll や exe を直指定する場合は、Edit Assembly List からの選択でなく Project -> Add Classes from Assembly File でも大丈夫かも。

完了ボタン押すと Environment にだだーと関連するパッケージが表示される。ここから Java ラッパーを作りたい .NET のクラスを選ぶ。ここではメンドイのでぜんぶ選ぶため Edit -> Check All in Environemnt して Add を押す。と、Exposed Proxies に色々と表示される。

次に Exposed Proxies から Java のラッパーを作りたいクラスを選ぶわけだが、メンドイのでぜんぶ選ぶために Edit -> Check All in Exposed Proxies を選択する。

最後に Project -> Build で jar ファイルの吐き出し先を指定して完了。名前はとりあえず hogehoge.jar とする。

作成したブリッジ経由 - Java から .NET のクラスを呼ぶ

今作成した hogehoge.jar にパスを通す。C:\Program Files\JNBridge\JNBridgePro v4.0\jnbcore\jnbcore.jar と C:\Program Files\JNBridge\JNBridgePro v4.0\jnbcore\bcel-5.1-jnbridge.jar にもパスを通す。コンパイルはこの 2 つの jar がないと通らない。

で、こんな感じに Java のコードを書きます。

package hoge;

import HogeHoge2.Class1;

import com.jnbridge.jnbcore.DotNetSide;

public class HogehogeMain {
	
	public static void main(String[] args) {
		DotNetSide.init("C:\\Program Files\\JNBridge\\JNBridgePro v4.0\\jnbcore\\jnbcore_tcp.properties");
		
		Class1 c1 = new Class1();
		int ret = c1.getAddAnswer(123, 40000);
		System.out.println(ret);
	}
}

DotNetSide.init で指定してるのは……まぁ「おまじない」といいますか。Java -> .NET 通信用の設定ファイルです。同ディレクトリには jnbcore_sharedmem.properties てのがあるので Shared memory の場合はこっちを使用するのだろう*1

この状態で動かすと下記のような例外を吐く。

Exception in thread "main" java.lang.NullPointerException
	at com.jnbridge.jnbcore.clientTransports.d$b.close(Unknown Source)
	at java.net.Socket.<init>(Socket.java:369)
	at java.net.Socket.<init>(Socket.java:209)
	at com.jnbridge.jnbcore.clientTransports.d$b.<init>(Unknown Source)
	at com.jnbridge.jnbcore.clientTransports.d.if(Unknown Source)
	at com.jnbridge.jnbcore.clientTransports.c.a(Unknown Source)
	at com.jnbridge.jnbcore.clientTransports.f.a(Unknown Source)
	at com.jnbridge.jnbcore.DotNetSideProxy.int(Unknown Source)
	at com.jnbridge.jnbcore.DotNetSideProxy.try(Unknown Source)
	at com.jnbridge.jnbcore.DotNetSideProxy.booleanStaticCall(Unknown Source)
	at com.jnbridge.jnbcore.h.y(Unknown Source)
	at com.jnbridge.jnbcore.DotNetSideProxy.int(Unknown Source)
	at com.jnbridge.jnbcore.DotNetSideProxy.construct(Unknown Source)
	at HogeHoge2.Class1.<init>()
	at hoge.HogehogeMain.main(HogehogeMain.java:12)

これは Java - .NET 間通信用のサーバが起動していないため。そのために C:\Program Files\JNBridge\JNBridgePro v4.0\2.0-targeted\JNBDotNetSide.exe を起動する。

C:\Program Files\JNBridge\JNBridgePro v4.0\2.0-targeted>JNBDotNetSide.exe
JNBDotNetSide, Copyright 2004-2008, JNBridge, LLC
Starting .NET-side server
Hit <return> to exit

と表示されれば起動完了。

この状態で動かすと下記のような例外を吐く。

Exception in thread "main" com.jnbridge.jnbcore.DotNetClassNotFoundException: HogeHoge2.Class1
   場所 com.jnbridge.jnbcore.JNBDotNetDispatcher.construct(String className, String[] signature, Object args)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
	at java.lang.reflect.Constructor.newInstance(Constructor.java:494)
	at com.jnbridge.jnbcore.DotNetObjectBase.a(Unknown Source)
	at com.jnbridge.jnbcore.ExceptionFactory.throwException(Unknown Source)
	at HogeHoge2.Class1.<init>()
	at hoge.HogehogeMain.main(HogehogeMain.java:12)

Java 側のブリッジクラスと .NET 側のクラスの対応付けが出来ないため DotNetClassNotFoundException というファンキーネームな例外を吐く。これを解消するために JNBDotNetSide.exe の設定ファイルを変更する必要がある。同ディレクトリの JNBDotNetSide.exe.config がソレ。このファイルの下記部分を書き換える。

    <!-- optional list of .NET-side assemblies -->
    <!--
    <assemblyList>
		<assembly file="path to first .NET-side assembly"/>
		<assembly file="path to second .NET-side assembly"/>
    </assemblyList>
    -->

    <assemblyList>
	<assembly file="C:/HogeHoge2.dll" />
    </assemblyList>

へ変更する。GAC のを使う場合はこんな感じ。file とか PublicKeyToken とかは適宜読みかえ願います。C:\WINDOWS\assembly にあるヤツを全部試したわけでないからちょっと自身無し。要マニュアル確認。

    <assemblyList>
      <assembly file="Microsoft.Nantara, Version=1.0.0.0, Culture=neutral,
		PublicKeyToken=1234567890abcdef" />
    </assemblyList>

JNBDotNetSide.exe.config を変更したら JNBDotNetSide.exe を起動して Java を走らせてみる。計算結果が返ってこれば無事 Java - .NET 通信完了。

感想

Java と他言語環境接続する類のブツは Java/JNI/Tool - discypus を見てもわかるとおり結構色んなものがあるのを最近知った。やはりそれだけ需要があるんだろうねぇ。純技術的には .NETJava をマゼコゼにするのはどーにもアレな気分なんだけど「.NET のブツがあるからそれ活かして Java で web アプリ作りたい(逆もアリ)」っていうビジネス的な要求から開発されてる代物なんだろうかね?

*1:ちなみに jnbcore_sharedmem.properties の dotNetSide.javaEntry は C:/Program Files/JNBridge/JNBridgePro v4.0/2.0-targeted/JNBJavaEntry.dll に変更しないと動かない気がする。古いバージョンの指定が残ってるだけぽいが、意外とこういうとこで「動かねぇー!」ってハマるからなぁ……w