28 février 2024

Traduction de C# à Java – Utiliser la logique du .NET Framework dans l'environnement Java

La traduction de certains projets d'un langage à un autre ne concerne pas seulement les modifications du code source, mais aussi l'environnement dans lequel nous exécutons ce projet. CodePorting.Translator Java Class Library implémente un tel environnement sur JCL (Java class library), en conservant la logique et la structure de la bibliothèque de classes du .NET Framework, ce qui permet à un projet traduit de se sentir chez lui, en le cachant de l'implémentation de la plateforme Java.

CodePorting.Translator Java Class Library

La JCL (Java class library) diffère de la bibliothèque de classes .NET dans la conception générale, la gestion des exceptions et la logique. Ainsi, si nous décidons de traduire notre code de C# en Java, il serait dangereux de simplement remplacer les noms des classes et des fonctions. Une solution pourrait être de générer du code d'enveloppe, qui reproduirait la logique de la bibliothèque de classes du .NET Framework. Mais, de cette façon, le code Java résultant différerait considérablement du code C# original, ce qui n'est pas ce que nous attendons – nous voulons qu'un traducteur conserve la structure originale du programme. Nous en venons donc à la nécessité d'implémenter un remplacement Java de la bibliothèque de classes du .NET Framework.

Comment ça fonctionne

Commençons par quelque chose de simple :

using System;

class Program
{
    public static void Main(string[] args)
    {
        Console.WriteLine("Hello, Example!");
    }
}

Nous avons ici une classe de la bibliothèque de classes du .NET Framework – System.Console. À quoi ressemblerait le code Java traduit ?

import com.codeporting.ms.System.Console;

class Program
{
    public static void main(String[] args)
    {
        Console.writeLine("Hello, Example!");
    }
}

Comme vous pouvez le voir, le traducteur remplace la référence de la classe C# System.Console par la classe Java com.codeporting.ms.System.Console, implémentée dans la CodePorting.Translator Java Class Library.

Eh bien, maintenant regardons un autre exemple :

using System;
using System.Collections.Generic;

class Program
{
    public static void Main(string[] args)
    {
        PrintList(new List<string> { "Hello, list!", "I have a list for you to print!" });
    }
    public static void PrintList(List<string> list)
    {
        foreach(var item in list) Console.WriteLine(item);
    }
}

Le code Java traduit serait ceci :

import com.codeporting.ms.System.Collections.Generic.IGenericEnumerable;
import com.codeporting.ms.System.Collections.Generic.List;
import com.codeporting.ms.System.Console;
import com.codeporting.ms.System.IDisposable;
import java.util.Iterator;

class Program
{
    public static void main(String[] args)
    {
        List<String> tmp = new List<String>();
        tmp.addItem("Hello, list!");
        tmp.addItem("I have a list for you to print!");
        printList(tmp);
    }
    public static void printList(IGenericEnumerable<String> list)
    {
        //Foreach to while statement conversion
        Iterator<String> variable1 = list.iterator();
        try
        {
            while (variable1.hasNext())
            {
                String item = variable1.next();
                Console.writeLine(item);
            }
        }
        finally
        {
            if (variable1 != null)
            {
                ((IDisposable)variable1).dispose();
            }
        }
    }
}

Ici, nous voyons un autre avantage de l'utilisation de CodePorting.Translator Java Class Library –- nous conservons les relations entre les abstractions C#. System.Collections.Generic.List implémente l'interface IEnumerable, ce qui nous permet de l'itérer en utilisant la boucle foreach. Java a l'interface java.lang.Iterable, et elle semble similaire à IEnumerable, mais elles ont de petites différences de conception, qui peuvent devenir décisives pour un grand projet.

Pureté de l'API publique

Bien que nous ayons une belle bibliothèque à utiliser, un projet que nous traduisons doit être accessible et compréhensible par les clients, et ils peuvent préférer utiliser les classes JCL. Il serait bon de cacher au monde extérieur que nous utilisons CodePorting.Translator Java Class Library. Et, ici, nous avons une autre caractéristique intéressante de CodePorting.Translator : ApiChange. Que fait cette fonctionnalité ? Elle cache les méthodes qui utilisent CodePorting.Translator Java Class Library, en créant des méthodes proxy qui utilisent les classes JCL. Regardons l'exemple :

using System;
using System.Collections.Generic;
using System.Linq;

namespace Newspaper
{
    public class Article
    {
        public DateTime Published { get; set; }
        public string Content { get; set; }
    }

    public class Archive
    {
        List<Article> articles = new List<Article>();

        public void AddArticle(Article article)
        {
            articles.Add(article);
        }

        public IEnumerable<Article> GetArticlesForPeriod(DateTime start, DateTime end)
        {
            if(start > end || start > DateTime.Now)
            {
                return new Article[0];
            }
            return articles.Where(article => article.Published >= start && article.Published <= end);
        }
    }

    public class Program
    {
        public static void Main(string[] args)
        {
            var archive = new Archive();
            archive.AddArticle(
                new Article() {
                    Published = new DateTime(2012, 12, 20), Content = "End of the world comes tomorrow!" });
            archive.AddArticle(
                new Article() {
                    Published = new DateTime(2012, 12, 22), Content = "It was a huge joke..." });
            var articles = archive.GetArticlesForPeriod(
                new DateTime(2000, 1, 1),
                new DateTime(2012, 12, 21));
            foreach(var article in articles)
            {
                Console.WriteLine(article.Content);
            }
        }
    }
}

Vous pouvez voir ici une classe simple Archive qui stocke des articles et fournit un accès à ceux-ci, en appliquant un filtre par la date à laquelle l'article a été publié. La classe System.DateTime fait partie de la bibliothèque de classes du .NET Framework, et, bien que nous puissions l'utiliser dans notre projet, nous aimerions la cacher au monde extérieur :

Article.java

package Newspaper;

import com.codeporting.ms.System.DateTime;
import java.util.Date;

public class Article
{
    private DateTime auto_Published = new DateTime();
    final DateTime getPublishedInternal() { return auto_Published.Clone(); }
    public final Date getPublished() {
        return DateTime.toJava(getPublishedInternal());
    }
    final void setPublishedInternal(DateTime value) { auto_Published = value.Clone(); }
    public final void setPublished(Date value) {
        setPublishedInternal(DateTime.fromJava(value));
    }
    private String auto_Content;
    public final String getContent() { return auto_Content; }
    public final void setContent(String value) { auto_Content = value; }
}

Archive.java

package Newspaper;

import com.codeporting.ms.System.Collections.Generic.IGenericEnumerable;
import com.codeporting.ms.System.Collections.Generic.List;
import com.codeporting.ms.System.DateTime;
import com.codeporting.ms.System.Func;
import java.util.Date;

public class Archive
{
    private Archive[] Archive_this = {this};
    private List<Article> articles = new List<Article>();

    public final void addArticle(Article article)
    {
        articles.addItem(article);
    }

    final IGenericEnumerable<Article> getArticlesForPeriodInternal(DateTime start, DateTime end)
    {
        if(DateTime.op_GreaterThan(start, end) || DateTime.op_GreaterThan(start, DateTime.getNow()))
        {
            return com.codeporting.ms.System.Array.<Article>toGenericList(new Article[0]);
        }
        return articles.where(new Func<Article,Boolean>() {
            public String getDelegateId() {
                return System.identityHashCode(Archive_this[0]) + "-89480671";
            }
            public Boolean invoke(Newspaper.Article article) {
                return DateTime.op_GreaterThanOrEqual(article.getPublishedInternal(), start) 
                    && DateTime.op_LessThanOrEqual(article.getPublishedInternal(), end);
            }
        });
    }

    public final java.lang.Iterable<Article> getArticlesForPeriod(Date start, Date end)
    {
        IGenericEnumerable<Article> temp=getArticlesForPeriodInternal(
            DateTime.fromJava(start),
            DateTime.fromJava(end));
        java.util.ArrayList<Article> temp_java=new java.util.ArrayList<Article>();
        {
            com.codeporting.ms.System.Collections.Generic.IGenericEnumerator<Article> temp_iterator=temp.iterator();
            while(temp_iterator.hasNext())
            {
                Article element=temp_iterator.next();
                temp_java.add(element);
            }
        }
        return temp_java;
    }
}

Program.java

package Newspaper;

import com.codeporting.ms.System.Collections.Generic.IGenericEnumerable;
import com.codeporting.ms.System.Console;
import com.codeporting.ms.System.DateTime;
import com.codeporting.ms.System.IDisposable;
import java.util.Iterator;

public class Program
{
    public static void main(String[] args)
    {
        Archive archive = new Archive();
        Article tmp = new Article();
        tmp.setPublishedInternal(new DateTime(2012, 12, 20));
        tmp.setContent("End of the world comes tomorrow!" ) ;
        archive.addArticle(tmp);
        Article tmp_1 = new Article();
        tmp_1.setPublishedInternal(new DateTime(2012, 12, 22));
        tmp_1.setContent("It was a huge joke..." ) ;
        archive.addArticle(tmp_1);
        IGenericEnumerable<Article> articles = archive.getArticlesForPeriodInternal(
	        new DateTime(2000, 1, 1),
	        new DateTime(2012, 12, 21));
        //Foreach to while statement conversion
        Iterator<Article> variable1 = articles.iterator();
        try
        {
            while (variable1.hasNext())
            {
                Article article = variable1.next();
                Console.writeLine(article.getContent());
            }
        }
        finally
        {
            if (variable1 != null)
            {
                ((IDisposable)variable1).dispose();
            }
        }
    }
}

Le code Java traduit n'offre pas d'accès à CodePorting.Translator Java Class Library via API publique, et le monde Java extérieur peut interagir avec notre classe Archive, en utilisant des méthodes proxy publiques.

Ce que nous pouvons conclure

CodePorting.Translator Java Class Library fournit une couche d'abstraction et un contrôle sur JCL, ce qui nous distrait des détails de mise en œuvre et nous permet de réfléchir aux problèmes que nous résolvons.
Il aide également à conserver la structure du code original, augmentant la compréhension et la transparence du résultat de la traduction.

Nouvelles connexes

Articles liés