<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>The World is mine &#187; interop</title>
	<atom:link href="http://grozeille.com/tag/interop/feed/" rel="self" type="application/rss+xml" />
	<link>http://grozeille.com</link>
	<description>Just another Wordpress.com weblog</description>
	<lastBuildDate>Sat, 07 Jan 2012 12:00:31 +0000</lastBuildDate>
	<language>fr</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<cloud domain='grozeille.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://s2.wp.com/i/buttonw-com.png</url>
		<title>The World is mine &#187; interop</title>
		<link>http://grozeille.com</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://grozeille.com/osd.xml" title="The World is mine" />
	<atom:link rel='hub' href='http://grozeille.com/?pushpress=hub'/>
		<item>
		<title>Appeler du Java depuis .Net</title>
		<link>http://grozeille.com/2008/05/08/appeler-du-java-depuis-net/</link>
		<comments>http://grozeille.com/2008/05/08/appeler-du-java-depuis-net/#comments</comments>
		<pubDate>Thu, 08 May 2008 18:34:15 +0000</pubDate>
		<dc:creator>Mathias Kluba</dc:creator>
				<category><![CDATA[Développement]]></category>
		<category><![CDATA[.Net]]></category>
		<category><![CDATA[c++]]></category>
		<category><![CDATA[interop]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[jni]]></category>

		<guid isPermaLink="false">http://grozeille.wordpress.com/?p=53</guid>
		<description><![CDATA[Deux mondes s&#8217;affrontent: Java et .Net. Chacun choisi son camp, ou choisi les deux&#8230; moi j&#8217;ai la double nationalité Mais quand les deux mondes doivent alors communiquer? Je fais l&#8217;interprète. Voila le topo: J&#8217;ai une application .Net qui a besoin de manipuler des classes Java, et pour se faire je passe par C++/CLI: comment avoir [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=grozeille.com&#038;blog=173450&#038;post=53&#038;subd=grozeille&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Deux mondes s&#8217;affrontent: Java et .Net. Chacun choisi son camp, ou choisi les deux&#8230; moi j&#8217;ai la double nationalité <img src='http://s0.wp.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  Mais quand les deux mondes doivent alors communiquer? Je fais l&#8217;interprète. Voila le topo:<br />
J&#8217;ai une application .Net qui a besoin de manipuler des classes Java, et pour se faire je passe par <a href="http://en.wikipedia.org/wiki/C%2B%2B/CLI">C++/CLI</a>: comment avoir un pied dans du .Net et un autre dans du natif C++.<br />
<span id="more-53"></span><br />
L&#8217;avantage de C++/CLI (<a href="http://en.wikipedia.org/wiki/Common_Language_Infrastructure">Common Language Infrastructure</a>) c&#8217;est qu&#8217;on peut mixer du code managé et non-managé. Je peux donc compiler un assembly .Net en C++, qui lui fait appelle à du pure code C++ natif. Ici en l&#8217;occurrence j&#8217;utilise <code>"jni.h"</code> pour communiquer avec la JVM à l&#8217;aide de <code>jvm.dll</code>.</p>
<p>Rentrons dans le vif du sujet: qu&#8217;est-ce que ça donne du coté de mon application C#:<br />
<pre class="brush: csharp;">
// on démarre la JVM avec mes bons arguments
MathiasJniCpp.JVMWrapper.InitJvm(new String[] { &quot;-Djava.class.path=Mathias.Jni.Java.jar&quot; });

// on créer un objet .Net qui wrappe l'objet Java
// en C++/CLI, le destructeur des classes CLI sert de méthode &quot;Dispose&quot;
using (MathiasJniCpp.MyJavaWrapper javaObject = new MathiasJniCpp.MyJavaWrapper())
{
// faire mumuse avec...
javaObject.People = &quot;Mathias&quot;;
Console.WriteLine(javaObject.SayHello());
}

// on libère la JVM
JVMWrapper.ReleaseJvm();
</pre></p>
<p><code>MathiasJniCpp</code> c&#8217;est le namespace de mon assembly c++/cli, j&#8217;en reparlerai plus tard.<br />
On voit que je manipule une classe JVMWrapper qui me permet de charger une JVM (et de la libérer). J&#8217;utilise aussi une classe .Net codé en C++/CLI. En fait, je l&#8217;utilise comme un classe C#, ou VB.net etc. C&#8217;est une classe &#8220;classique&#8221; .Net avec des méthodes et des propriétés.</p>
<p>Point intéressant à souligner: pourquoi utiliser <code>using</code>?<br />
Pour rappelle, il y a des mots-clefs en C# très lié au Framework (comme <code>foreach</code>) et <code>using</code> en fait partie. Il prend les objets qui implémente <code>IDisposable</code> et fait appelle à la méthode <code>Dispose()</code> à la fin du bloque. Comme ça, je suis sûr de libérer la classe du coté JVM quand j&#8217;en ai plus besoin.</p>
<p>Je ne vais pas montrer tout le code, car trop long et <a href="http://www.box.net/shared/ropzl4u80o">disponible ici</a>.<br />
Mais voici un aperçu de la classe C++:<br />
<pre class="brush: cpp;">
#include &quot;jni.h&quot;
public ref class MyJavaWrapper
{
private:
  static jmethodID initMethodId;
  static jclass clazz;
  jobject obj;
public:
  /* initialisation des métadata Java/JNI, à voir plus tard */
  static void initJavaMetadata()
  { ... }

  /* une méthode de notre classe Java que l'on wrappe, expliqué aussi plus tard */
  String^ SayHello(String^ people)
  { ... }

  /* constructeur */
  MyJavaWrapper(void)
  {
    // histoire de récupérer toutes les métadatas nécessaires du coté Java
    MyJavaWrapper::initJavaMetadata();

    // construction d'une instance avec le constructeur par défaut
    this-&gt;obj = JVMWrapper::env-&gt;NewObject(MyJavaWrapper::clazz, MyJavaWrapper::initMethodId);
  }

  /* &quot;destructeur&quot; */
  virtual ~MyJavaWrapper(void)
  {
    JVMWrapper::env-&gt;DeleteLocalRef(this-&gt;obj);
  }
};
</pre><br />
<code>ref class</code> veut dire &#8220;c&#8217;est une classe .Net&#8221;. Mais&#8230; ma classe n&#8217;implémente pas <code>IDisposable</code>!! Et c&#8217;est quoi ce destructeur??<br />
Et oui: le destructeur C++ pour un objet .Net est transformé en la méthode <code>Dispose()</code> et la classe devient alors forcement <code>IDisposable</code>. Pour gérer le <code>finalize</code> <a href="http://dotnet.developpez.com/faq/cppcli/?page=syntaxe#finalizer_vs_destructor">allez voir ici</a>.</p>
<p>Je manipule le membre <code>this-&gt;obj</code> qui est tout simplement un &#8220;pointeur&#8221; sur notre objet java. En fait, c&#8217;est un <code>jobject</code> qui est un type définie dans <code>"jni.h"</code>.<br />
J&#8217;utilise la classe JVMWrapper qui me permet de communiquer avec la JVM, et je lui demande de créer un nouvel objet d&#8217;une certaine classe <code>jclass</code> avec un certain constructeur <code>jmethodID</code> et j&#8217;obtiens ainsi mon <code>jobject</code>.<br />
<em>Étant donnée que la classe et la méthode ne change pas, j&#8217;ai rendu ces données <code>static</code>.</em></p>
<p>Voyons maintenant ce que fait <code>MyJavaWrapper::initJavaMetadata();</code>:<br />
<pre class="brush: cpp;">
/* initialise les metadata du coté Java */
static void initJavaMetadata()
{
  // si les métadata ne sont pas déjà récupérées...
  if(MyJavaWrapper::clazz == NULL)
  {
    MyJavaWrapper::clazz = JVMWrapper::env-&gt;FindClass(&quot;mathias/jni/java/MyJavaClass&quot;);
    MyJavaWrapper::initMethodId = JVMWrapper::env-&gt;GetMethodID(MyJavaWrapper::clazz, &quot;&lt;init&gt;&quot;, &quot;()V&quot;);
  }
}
</pre></p>
<p>C&#8217;est la dedans que j&#8217;obtiens une fois pour toute la représentation de la classe Java <code>mathias.jni.java.MyJavaClass</code> et la représentation de la méthode <code>&lt;init&gt;</code> avec en paramètre <code>()V</code>.<br />
Pour comprend le lien avec la classe, il n&#8217;y a pas trop de problème: c&#8217;est le <a href="http://en.wikipedia.org/wiki/Fully_qualified_name">fully qualified name</a> avec des &#8216;/&#8217; au lieu des &#8216;.&#8217;.<br />
Mais en ce qui concerne la recherche d&#8217;une méthode, ça devient du charabia!!<br />
En fait, <code>&lt;init&gt;</code> est une méthode un peu spéciale: c&#8217;est un constructeur.<br />
Ensuite, on spécifie les arguments du constructeur que l&#8217;on cherche, et la on tombe sur une syntaxe barbare. Dans notre cas, on cherche le constructeur par défaut c&#8217;est à dire qui ne prend pas d&#8217;argument.<br />
Mais pour mieux comprendre la syntaxe barbare, voyons d&#8217;autres exemples de méthodes:<br />
<pre class="brush: cpp;">
JVMWrapper::env-&gt;GetMethodID(MyJavaWrapper::clazz, &quot;setPeople&quot;, &quot;(Ljava/lang/String;)V&quot;);
</pre><br />
Traduction: je cherche la méthode <code>setPeople</code> qui prend un argument de type <code>java.lang.String</code> et qui retourne <code>void</code>.<br />
Un autre exemple:<br />
<pre class="brush: cpp;">
JVMWrapper::env-&gt;GetMethodID(MyJavaWrapper::clazz, &quot;sayHello&quot;, &quot;([Ljava/lang/String;Z;)I&quot;);
</pre><br />
Traduction: je cherche la méthode <code>sayHello</code> qui prend un argument de type <code>java.lang.String[]</code> et un autre de type <code>boolean</code> et qui retourne un type <code>int</code>.</p>
<p>On retrouve cette syntaxe à beaucoup d&#8217;endroits, comme sous <a href="http://grozeille.files.wordpress.com/2008/05/eclipsejni.png">Eclipse</a> par exemple. Pour plus d&#8217;explication voir la <a href="http://java.sun.com/j2se/1.4.2/docs/guide/jni/spec/types.html">documentation officielle</a>.</p>
<p>Si l&#8217;on veut maintenant appeler une méthode Java, on récupère sa représentation tout comme on le fait avec le constructeur, puis on l&#8217;invoque sur notre instance:<br />
<pre class="brush: csharp;">
public ref class MyJavaWrapper
{
private:
  static jmethodID initMethodId;
  static jclass clazz;

  // notre représentation JNI de la méthode &quot;sayHello&quot;
  static jmethodID sayHelloMethodId;

  jobject obj;
public:
  /* initialisation des métadata Java/JNI */
  static void initJavaMetadata()
  { 
    /* initialisation de la classe et du constructeur, comme vu précédemment 
    [...]  */

    // on récupère la représentation de &quot;sayHello&quot;
    JVMWrapper::env-&gt;GetMethodID(MyJavaWrapper::clazz, &quot;sayHello&quot;, &quot;(Ljava/lang/String;)Ljava/lang/String&quot;);
  }

  /* sur l'appelle de cette méthode .Net, on fait appelle à la méthode Java */
  String^ SayHello(String^ people)
  {
    // j'utilise une classe spéciale pour convertir ma String^ .net en natif ou Java
    StringConverter peopleStringConverter(people);
    jstring jPeople = peopleStringConvert.toJava();

    // appelle de la méthode Java, j'ai le droit de caster en jstring car c'est un sous-type de jobject
    jstring jResult = (jstring)JVMWrapper::env-&gt;CallObjectMethod(this-&gt;obj, sayHelloMethodId, jPeople);

    // conversion du type Java en .Net
    StringConverter resultStringConvert(jResult);
    return resultStringConvert.toDotnet();
  }
};
</pre></p>
<p>Voila, maintenant vous savez:</p>
<ul>
<li>obtenir la représentation d&#8217;une classe Java</li>
<li>obtenir la représentation d&#8217;une méthode d&#8217;une classe</li>
<li>créer une instance d&#8217;une classe Java</li>
<li>invoker des méthodes sur une instance</li>
</ul>
<p>En conclusion:<br />
l&#8217;API JNI c&#8217;est un peux comme utiliser la réflection. Ça a donc des conséquences en termes de performance. Pour information, créer 10000 objet en java prend <em>625ms</em>, en pure .net ça donne <em>46ms</em> et en .Net-&gt;JNI-&gt;Java ça donne <em>2.687s</em>.<br />
L&#8217;API JNI peut sembler barbare au début, mais on s&#8217;y fait <img src='http://s0.wp.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  et puis il y a <a href="http://java.sun.com/j2se/1.4.2/docs/guide/jni/spec/functions.html#wp20949">la doc</a>, alors <a href="http://en.wikipedia.org/wiki/RTFM">RTFM</a> <img src='http://s1.wp.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> .</p>
<p>C++/CLI c&#8217;est de la bombe en termes d&#8217;interop. C&#8217;est le pont parfait entre le monde .Net et le natif.<br />
L&#8217;inconvénient c&#8217;est que la syntaxe C++ est lourde. Et elle l&#8217;est d&#8217;autant plus en C++/CLI car il faut y ajouter les spécificités .Net, et il faut aussi distinguer une instance managée et non-managée, et tout ça passe par de nouveau symboles/mots-clefs.<br />
Les conversions de types entre les deux mondes ne sont pas faites implicitement, et il faut souvent jongler pour avoir le bon type. J&#8217;ai par exemple eu des problèmes lors des conversions de String avec JNI: il faut convertir la <code>String^</code> .net en <code>char*</code> natif pour enfin construire une <code>jstring</code>. Les conversions ont été le plus pénible dans l&#8217;histoire.</p>
<p>Enfin, voici le projet complet: <a href="http://www.box.net/shared/ropzl4u80o">Mathias.Jni.CSharp.zip</a><br />
Un petit rappel des liens utiles:</p>
<ul>
<li><a href="http://dotnet.developpez.com/faq/cppcli/">http://dotnet.developpez.com/faq/cppcli/</a></li>
<li><a href="http://java.sun.com/j2se/1.4.2/docs/guide/jni/spec/jniTOC.html">http://java.sun.com/j2se/1.4.2/docs/guide/jni/spec/jniTOC.html</a></li>
</ul>
<br /><img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/grozeille.wordpress.com/53/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/grozeille.wordpress.com/53/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/grozeille.wordpress.com/53/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/grozeille.wordpress.com/53/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/grozeille.wordpress.com/53/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/grozeille.wordpress.com/53/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/grozeille.wordpress.com/53/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/grozeille.wordpress.com/53/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/grozeille.wordpress.com/53/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/grozeille.wordpress.com/53/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/grozeille.wordpress.com/53/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/grozeille.wordpress.com/53/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/grozeille.wordpress.com/53/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/grozeille.wordpress.com/53/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/grozeille.wordpress.com/53/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/grozeille.wordpress.com/53/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=grozeille.com&#038;blog=173450&#038;post=53&#038;subd=grozeille&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://grozeille.com/2008/05/08/appeler-du-java-depuis-net/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/fcf307a3a2899d162cabfd41241f17b9?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">grozeille</media:title>
		</media:content>
	</item>
	</channel>
</rss>
