Vous êtes nouveau sur Developpez.com ? Créez votre compte ou connectez-vous afin de pouvoir participer !

Vous devez avoir un compte Developpez.com et être connecté pour pouvoir participer aux discussions.

Vous n'avez pas encore de compte Developpez.com ? Créez-en un en quelques instants, c'est entièrement gratuit !

Si vous disposez déjà d'un compte et qu'il est bien activé, connectez-vous à l'aide du formulaire ci-dessous.

Identifiez-vous
Identifiant
Mot de passe
Mot de passe oublié ?
Créer un compte

L'inscription est gratuite et ne vous prendra que quelques instants !

Je m'inscris !

Interopérabilité Java/.NET avec IKVM : apprendre à utiliser du code écrit en Java depuis un code C#
Un tutoriel de François DORIN

Le , par François DORIN

0PARTAGES

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 :


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) :
Code : Sélectionner tout
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 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.

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
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(); 
        }
Code C# : Sélectionner tout
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; 
        } 
    }
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.

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 !

Une erreur dans cette actualité ? Signalez-le nous !