[Actualité] Interopérabilité Java/.NET avec IKVM : utiliser du code écrit en Java depuis un code C#
par
, 08/04/2018 à 23h18 (5784 Affichages)
Bonjour,
Dans le billet du jour, nous allons avoir comment nous pouvons intégrer une classe, écrite initialement en Java, directement en C#, à travers un exemple concret : générer un PDF à partir de la bibliothèque Apache FOP.
Cela ne serait pas possible aussi facilement sans le projet IKVM.NET, qui est une implémentation de Java pour environnement .Net (Mono et le framework .NET de Microsoft).
Ce billet étant axé sur l'interopérabilité entre Java/.NET, je ne m'attarderai pas sur l'usage de Apache FOP.
Principe
Le principe retenu ici est assez simple.
Dans un premier temps, on va convertir le fichier .jar de la bibliothèque Apache FOP en un assembly .NET. Pour ce faire, on va utiliser l'utilitaire ikvmc qui permet de convertir le bytecode Java en assembly .NET.
Dans un second temps, on va utiliser cet assembly au sein d'un programme C#.
Préparation
Avant de procéder à la génération de l'assembly,il nous faut récupérer l'ensemble des outils nécessaires via leur site respectif :
- IKVM : https://www.ikvm.net/
- Apache FOP : https://www.ikvm.net/
Une fois les outils téléchargés, il faudra les extraire dans le dossier de votre choix.
Conversion .jar vers .dll
Ici, pas grand chose à faire. Si ce n'est exécuter le petit script suivant (avec quelques modifications en fonction de votre installation) :
La première partie du script permet d'indiquer où se trouve le binaire de IKVM que vous avez téléchargé à l'étape précédente. Au passage, on peut voir que pour ma part, j'utilise la version 7.2.4630.5.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 SET IKVM_BIN_PATH=C:\Users\fdori\Downloads\ikvmbin-7.2.4630.5\ikvm-7.2.4630.5\bin set PATH=%PATH%;%IKVM_BIN_PATH% ikvmc -target:library *.jar ../build/fop.jar -out:fop.dll
La dernière ligne du script est celle qui procède effectivement à la conversion .jar -> .dll. Elle doit être exécuté dans le sous-répertoire fop/lib de l'archive contenant Apache FOP.
Les paramètres passés sont les suivants (voir doc officielle pour plus d'informations) :
- -target: library : on indique ici que l'on souhaite généré un assembly .dll. Les autes cibles possibles sont "exe" pour une application console et "winexe" pour une application graphique ;
- *.jar : on indique ici les fichiers à inclure. Pour des raisons de simplicité, et dans la mesure où Apache FOP vient avec l'ensemble de ses dépendances, on utilise le caractère générique * ;
- out:fop.dll : nom du fichier de sortie, c'est-à-dire ici de l'assembly qui sera généré.
Mise en oeuvre
Maintenant que nous disposons de l'assembly fop.dll, nous pouvons l'utiliser dans un projet C# (ou VB.NET) classique. Il suffit d'ajouter à notre projet la référence de l'assembly que nous venons de générer.
Vous aurez aussi besoin de référencer des assemblys du projet IVMK. Pour Apache FOP, j'ai ûu référencer les assemblys suivants :
- IKVM.OpenJDK.Core ;
- IKVM.OpenJDK.XML.API ;
- IKVM.OpenJDK.XML.Transporm.
Le premier sera nécessaire dans tous les cas, car il contient les routines de bases de l'API Java.
Et maintenant le code :
Code C# : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38 public static void GenererPDF(System.Xml.XmlDocument source, string sourceToFOPXsltFileName, string ouputFileName) { // Récupération du fichier XSL System.Xml.Xsl.XslCompiledTransform xslt = new System.Xml.Xsl.XslCompiledTransform(); xslt.Load(sourceToFOPXsltFileName); // Génération du fichier FOP string foFileName = System.IO.Path.GetTempFileName(); using (System.Xml.XmlTextWriter writer = new System.Xml.XmlTextWriter(foFileName, System.Text.Encoding.UTF8)) { xslt.Transform(source.CreateNavigator(), null, writer); writer.Close(); } // Création du PDF par interop IKVM avec ApacheFOP java.io.File fo = new java.io.File(foFileName); java.io.File pdf = new java.io.File(ouputFileName); org.apache.fop.apps.FopFactory fopFactory = GetFactory(); org.apache.fop.apps.FOUserAgent foUserAgent = fopFactory.newFOUserAgent(); java.io.OutputStream sortie = new java.io.BufferedOutputStream(new java.io.FileOutputStream(pdf)); org.apache.fop.apps.Fop fop = fopFactory.newFop("application/pdf", foUserAgent, sortie); javax.xml.transform.TransformerFactory factory = javax.xml.transform.TransformerFactory.newInstance(); javax.xml.transform.Transformer transformer = factory.newTransformer(); javax.xml.transform.Source src = new javax.xml.transform.stream.StreamSource(fo); javax.xml.transform.Result res = new javax.xml.transform.sax.SAXResult(fop.getDefaultHandler()); transformer.transform(src, res); sortie.close(); } public static FopFactory GetFactory() { ResourceResolver myResolver = new MyResolver(); File file = new File(fop_dir); FopFactoryBuilder builder = new FopFactoryBuilder(file.toURI(), myResolver); FontManager fontManager = builder.getFontManager(); return builder.build(); }La classe MyResolver est une implémentation très basique et améliorable que nécessite Apache FOP pour récupérer les ressources externes.
Code C# : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 public class MyResolver : ResourceResolver { public OutputStream getOutputStream(URI uri) { return null; } /// <summary> /// Méthode appelée pour récupérer des ressources externes, comme les images /// </summary> /// <param name="uri"></param> /// <returns></returns> public Resource getResource(URI uri) { return null; } }
Conclusion
Comme on peut le constater, l'utilisation de IKVM est assez simple et permet d'utiliser une bibliothèque Java en C# avec un minimum d'effort. Cette approche n'est pas encore parfaite et peut parfois rencontrer quelques bugs, mais le fait qu'un projet de la taille d'Apache FOP soit supporté est quand même très encourageant.
Il peut tout à fait être utilisé pour gérer une partie non critique d'une application (comme la génération de PDF, comme dans cet exemple).
Il existe également d'autres méthodes pour interfacer du code Java et .NET. L'approche de IKVM est intéressante dans la mesure où elle se base sur une conversion du bytecode Java en assembly. Autrement dit, il n'est pas nécessaire d'avoir une JVM d'installer pour pouvoir utiliser le code converti !