Compilation Java - Existe-t-il un moyen d'indiquer au compilateur d'ignorer certaines parties de mon code?

StackOverflow https://stackoverflow.com/questions/74171

  •  09-06-2019
  •  | 
  •  

Question

Je gère une application Java Swing.

Pour assurer la compatibilité ascendante avec java 5 (pour les machines Apple), nous maintenons deux bases de code, l'une utilisant les fonctionnalités de Java 6, une autre sans ces fonctionnalités.

Le code est en grande partie identique, à l'exception des classes 3-4 qui utilisent les fonctionnalités de Java 6.

Je souhaite juste maintenir 1 code base. Existe-t-il un moyen lors de la compilation d’obtenir du compilateur Java 5 qu’il «ignore» certaines parties de mon code?

Je ne souhaite pas simplement commenter / supprimer le commentaire d'un élément de mon code, en fonction de la version de mon compilateur java.

Était-ce utile?

La solution

En supposant que les classes ont des fonctionnalités similaires avec des différences d’implémentation de 1,5 à 6,0, vous pouvez les fusionner en une seule classe. Ensuite, sans modifier le code source afin de le commenter / commenter, vous pouvez compter sur l'optimisation toujours effectuée par le compilateur. Si une expression if est toujours fausse, le code de l'instruction if ne sera pas inclus dans la compilation.

Vous pouvez créer une variable statique dans l'une de vos classes pour déterminer la version à exécuter:

public static final boolean COMPILED_IN_JAVA_6 = false;

Ensuite, demandez aux classes concernées de vérifier cette variable statique et de placer les différentes sections de code dans une simple instruction if

if (VersionUtil.COMPILED_IN_JAVA_6) {
  // Java 6 stuff goes here
} else {
  // Java 1.5 stuff goes here
}

Ensuite, lorsque vous voulez compiler l'autre version, il vous suffit de modifier cette variable et de la recompiler. Cela peut rendre le fichier java plus volumineux, mais cela consolidera votre code et éliminera toute duplication de code que vous avez. Votre éditeur peut se plaindre d’un code inaccessible ou de quoi que ce soit, mais le compilateur doit l’ignorer de manière heureuse.

Autres conseils

Les suggestions relatives à l'utilisation de chargeurs de classes personnalisés et de code commenté dynamiquement sont un peu incrédules en ce qui concerne la maintenance et la préservation de la santé de n'importe quelle âme pauvre qui prend le projet en main après avoir passé à la vitesse supérieure.

La solution est facile. Extrayez les classes affectées dans deux projets indépendants distincts - assurez-vous que les noms de paquetages sont identiques et compilez-les simplement dans des fichiers jar que vous pourrez ensuite utiliser dans votre projet principal. Si vous conservez les mêmes noms de package et les signatures de méthode, aucun problème - déposez simplement la version du fichier jar dont vous avez besoin dans votre script de déploiement. Je suppose que vous exécutez des scripts de construction distincts ou que vous avez des cibles distinctes dans le même script. Ant et maven peuvent facilement gérer la capture conditionnelle de fichiers et leur copie.

Je pense que la meilleure approche consiste probablement à utiliser des scripts de génération. Vous pouvez avoir tout votre code au même endroit. En choisissant les fichiers à inclure et ceux à ne pas inclure, vous pouvez choisir la version de votre code à compiler. Notez que cela ne vous aidera peut-être pas si vous avez besoin d’un contrôle plus fin que celui par fichier.

Vous pouvez probablement refactoriser votre code afin que la compilation conditionnelle ne soit vraiment pas nécessaire, mais simplement le chargement de classes conditionnel. Quelque chose comme ça:

public interface Opener{

public void open(File f);

 public static class Util{
        public Opener getOpener(){
          if(System.getProperty("java.version").beginsWith("1.5")){
           return new Java5Opener();
          }
          try{ 
            return new Java6Opener();
           }catch(Throwable t){
            return new Java5Opener();
           }
        }
 }

}

Cela pourrait nécessiter beaucoup d’effort en fonction du nombre de morceaux de code spécifiques à votre version.

Conserver un "maître" racine source créée sous JDK 5. Ajoutez une deuxième racine source parallèle à créer sous JDK version 6 ou supérieure. (Il ne devrait y avoir aucun chevauchement, c’est-à-dire aucune classe présente dans les deux.) Utilisez une interface pour définir le point d’entrée entre les deux et un minuscule reflet.

Par exemple:

---%<--- main/RandomClass.java
// ...
if (...is JDK 6+...) {
    try {
        JDK6Interface i = (JDK6Interface)
            Class.forName("JDK6Impl").newInstance();
        i.browseDesktop(...);
    } catch (Exception x) {
        // fall back...
    }
}
---%<--- main/JDK6Interface.java
public interface JDK6Interface {
    void browseDesktop(URI uri);
}
---%<--- jdk6/JDK6Impl.java
public class JDK6Impl implements JDK6Interface {
    public void browseDesktop(URI uri) {
        java.awt.Desktop.getDesktop().browse(uri);
    }
}
---%<---

Vous pouvez les configurer en tant que projets distincts dans un IDE utilisant différents JDK, etc. Le fait est que la racine principale peut être compilée indépendamment et il est très clair que vous pouvez utiliser quelle racine, alors que si vous essayez de compiler différents parties d'une même racine séparément, il est trop facile de "fuir" accidentellement utilisation de JDK 6 dans les mauvais fichiers.

Plutôt que d’utiliser Class.forName de la sorte, vous pouvez également utiliser un système d’enregistrement de service - java.util.ServiceLoader (si main pouvait utiliser JDK 6 et que vous souhaitiez une prise en charge optionnelle de JDK 7!), NetBeans Lookup, Spring , etc. etc.

La même technique peut être utilisée pour créer un support pour une bibliothèque optionnelle plutôt que pour un nouveau JDK.

Pas vraiment, mais il existe des solutions de contournement. Voir http://forums.sun.com/thread.jspa?threadID=154106& messageID = 447625

Cela dit, vous devez vous en tenir à au moins une version de fichier pour Java 5 et une autre pour Java 6, et les inclure via une construction ou une fabrication appropriée. Conserver tout cela dans un seul gros fichier et essayer d’obtenir que le compilateur à 5 ignore les choses qu’il ne comprend pas n’est pas une bonne solution.

HTH

- nikki -

Cela va faire frémir tous les puristes de Java (ce qui est amusant, heh heh) mais j'utiliserais le préprocesseur C, mettre #ifdefs dans mon source. Un makefile, un rakefile ou tout autre contrôle de votre construction devrait exécuter cpp pour créer un fichier temporaire destiné à alimenter le compilateur. Je ne sais pas si ant pourrait être fait pour faire cela.

Bien que stackoverflow semble être le lieu pour toutes les réponses, vous ne pouvez en aucun cas regarder plus loin vers http://www.javaranch.com pour la sagesse Java. J'imagine que cette question a déjà été traitée il y a très longtemps.

Cela dépend des fonctionnalités de Java 6 que vous souhaitez utiliser. Pour une chose simple, comme l’ajout de trieurs de lignes à JTables, vous pouvez réellement tester lors de l’exécution:

private static final double javaVersion =
         Double.parseDouble(System.getProperty("java.version").substring(0, 3));
private static final boolean supportsRowSorter =
         (javaVersion >= 1.6);

//...

if (supportsRowSorter) {
    myTable.setAutoCreateRowSorter(true);
} else {
    // not supported
}

Ce code doit être compilé avec Java 6, mais peut être exécuté avec n’importe quelle version (aucune nouvelle classe n’est référencée).

EDIT: pour être plus correct, il fonctionnera avec n’importe quelle version depuis la version 1.3 (selon cette page ).

Vous pouvez effectuer toutes vos compilations exclusivement sur Java6, puis utiliser System.getProperty ("java.version") pour exécuter de manière conditionnelle le chemin de code Java5 ou Java6.

Vous pouvez avoir du code exclusivement Java6 dans une classe et celle-ci fonctionnera correctement sous Java5 tant que le chemin du code réservé à Java6 n'est pas exécuté.

C’est un truc utilisé pour écrire des applets qui fonctionneront sur l’ancienne MSJVM jusqu’aux toutes nouvelles machines virtuelles Java de plug-in.

Il n'y a pas de pré-compilateur en Java. Donc, pas moyen de faire un # ifdef comme en C. Construire des scripts serait le meilleur moyen.

Vous pouvez obtenir une compilation conditionnelle, mais pas très bien - javac ignorera le code inaccessible. Ainsi, si vous avez structuré votre code correctement, vous pouvez faire en sorte que le compilateur ignore certaines parties de votre code. Pour utiliser cela correctement, vous devez également transmettre les arguments corrects à javac afin que celui-ci ne signale pas le code inaccessible sous forme d’erreurs et refuse de compiler: -)

.

La solution finale publique statique mentionnée ci-dessus présente un avantage supplémentaire que l'auteur n'a pas mentionné: si je comprends bien, le compilateur le reconnaîtra au moment de la compilation et compilera tout code contenu dans une instruction if qui fait référence à celle-ci. variable finale.

Je pense donc que c'est la solution exacte que vous recherchiez.

Une solution simple pourrait être:

  • Placez les classes divergentes en dehors de votre chemin de classe normal.
  • Écrivez un chargeur de classe personnalisé simple et installez-le dans main par défaut.
  • Pour toutes les classes, à l'exception de celles sur 5/6, Cassloader peut s'en remettre à son parent (le chargeur de classe système normal)
  • Pour les 5/6 (qui devraient être les seuls que le parent ne puisse pas trouver), il peut décider lequel utiliser via la propriété "os.name" ou l'une des vôtres.

Vous pouvez utiliser l'API de réflexion. mettez tout votre code 1.5 dans une classe et 1,6 api dans une autre. Dans votre script ant, créez deux cibles, une pour 1.5 qui ne compilera pas la classe 1.6 et une pour 1.6 qui ne compilera pas la classe pour 1.5. dans votre code, vérifiez votre version de Java et chargez la classe appropriée en utilisant la méthode de réflexion. Ainsi, javac ne se plaindra pas des fonctions manquantes. Voici comment je peux compiler mes applications MRJ (Mac Runtime pour Java) sous Windows.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top