Java-Kompilierung – Gibt es eine Möglichkeit, den Compiler anzuweisen, Teile meines Codes zu ignorieren?

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

  •  09-06-2019
  •  | 
  •  

Frage

Ich pflege eine Java Swing-Anwendung.

Aus Gründen der Abwärtskompatibilität mit Java 5 (für Apple-Maschinen) pflegen wir zwei Codebasen, eine mit Funktionen von Java 6 und eine andere ohne diese Funktionen.

Der Code ist weitgehend derselbe, mit Ausnahme von 3–4 Klassen, die Java 6-Funktionen verwenden.

Ich möchte nur eine Codebasis beibehalten.Gibt es beim Kompilieren eine Möglichkeit, den Java 5-Compiler dazu zu bringen, einige Teile meines Codes zu „ignorieren“?

Ich möchte nicht einfach Teile meines Codes kommentieren/auskommentieren, abhängig von der Version meines Java-Compilers.

War es hilfreich?

Lösung

Unter der Annahme, dass die Klassen eine ähnliche Funktionalität haben mit 1,5 vs. 6,0 Unterschiede bei der Umsetzung Sie sie in einer Klasse zusammenführen könnte. Dann, ohne die Quelle Bearbeitung / uncomment zu kommentieren, können Sie sich auf die Optimierung verlassen, die der Compiler immer tun. Wenn ein, wenn Ausdruck immer falsch ist, wird der Code in dem if-Anweisung nicht in der Sammlung enthalten sein.

Sie können eine statische Variable in einer Ihrer Klassen machen, um zu bestimmen, welche Version Sie ausführen möchten:

public static final boolean COMPILED_IN_JAVA_6 = false;

Und dann haben die betroffenen Klassen prüfen, ob statische Variable und setzen Sie die verschiedenen Abschnitte des Codes in einem einfachen if-Anweisung

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

Wenn Sie dann die andere Version kompilieren wollen Sie müssen nur die eine Variable ändern und neu kompilieren. Es könnte die Java-Datei größer machen, aber es wird Ihren Code konsolidieren und jede Code-Duplizierung beseitigen, die Sie haben. Der Editor kann über nicht erreichbaren Code beschweren oder was auch immer, aber der Compiler sollte selig ignoriert es.

Andere Tipps

Die Vorschläge zu benutzerdefinierten Klassenlader verwenden und dynamisch kommentierte Code sind ein wenig skeptisch, wenn es um Wartung und die Erhaltung der geistige Gesundheit von welcher auch immer arme Seele nimmt das Projekt, nachdem Sie mischen zu neuen Ufern.

Die Lösung ist einfach. Ziehen Sie die betroffenen Klassen heraus in zwei separate, unabhängige Projekte - stellen Sie sicher, dass die Paketnamen identisch sind, und kompilieren nur in Gläser, die Sie dann in Ihrem Hauptprojekt verbrauchen kann. Wenn Sie die Paketnamen die gleichen bleiben, und die Methodensignaturen, die gleiche, keine Probleme - fallen nur je nachdem, welche Version des jar Sie in Ihrem Bereitstellungsskript benötigen. Ich würde annehmen, dass Sie separaten Build-Skripte oder verfügen über separate Ziele im selben Skript laufen -. Ant und Maven können beide leicht handhaben bedingt Dateien packen und zu kopieren

Ich denke, der beste Ansatz ist hier wahrscheinlich Skripte zu verwenden, bauen. Sie können alle Ihre Code haben an einem Ort, und durch die Wahl, die Include-Dateien, und welche nicht zu enthalten, Sie, welche Version des Codes können wählen, zu kompilieren. Beachten Sie, dass dies nicht helfen, wenn Sie eine feinere Auswahl benötigen als pro Datei.

Sie können wahrscheinlich Ihren Code Refactoring, so dass bedingte Kompilierung wirklich nicht benötigt wird, nur bedingt Classloading. So etwas wie folgt aus:

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();
           }
        }
 }

}

Dieses viel Aufwand sein könnte, je nachdem wie viele versionsspezifische Stücke von Code, den Sie haben.

Halten ein „Master“ source Wurzel, die 5. In einer zweiten parallelen Quelle root unter JDK erstellt, die unter JDK 6 oder höher zu bauen hat. (Es sollte keine Überlappung sein, das heißt keine Klassen in beiden.) Eine Schnittstelle verwenden, den Eintrittspunkt zwischen den beiden, und ein klein wenig Reflexion zu definieren.

Zum Beispiel:

---%<--- 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);
    }
}
---%<---

Sie können diese als separate Projekte in einer IDE mit verschiedenen JDKs konfigurieren usw. Der Punkt ist, dass die Hauptwurzel unabhängig kompiliert werden kann, und es ist ganz klar, was Sie in den root verwenden können, während, wenn Sie versuchen, anders zu kompilieren Teile einer einzigen Wurzel getrennt ist es zu einfach aus Versehen „Leck“ Verwendung von JDK 6 in die falschen Dateien.

Anstatt Class.forName wie diese verwenden, können Sie auch eine Art von Service-Registrierungssystem verwenden - java.util.ServiceLoader (wenn Haupt 6 JDK verwenden könnte und Sie optionale Unterstützung für JDK 7 gesucht!), NetBeans Lookup, Frühling etc. etc.

Die gleiche Technik verwendet werden kann, Unterstützung für eine optionale Bibliothek zu erstellen, anstatt eine neuere JDK.

Nicht wirklich, aber es gibt Abhilfen. Sehen http://forums.sun.com/thread.jspa?threadID=154106&messageID= 447.625

Das heißt, Sie mit zumindest mit einer Dateiversion für Java 5 und eine für Java 6 bleiben sollte, und schließen sie über einen Build oder gegebenenfalls machen. Das Festhalten alles in einer großen Datei und versuchen, den Compiler für 5 zu bekommen Zeug zu ignorieren es nicht versteht, ist keine gute Lösung.

HTH

- nikki -

Das wird alle Java-Puristen zum Schaudern bringen (was Spaß macht, heh heh), aber ich würde den C-Präprozessor verwenden und #ifdefs in meine Quelle einfügen.Ein Makefile, Rakefile oder was auch immer Ihren Build steuert, müsste cpp ausführen, um temporäre Dateien zu erstellen, die den Compiler versorgen.Ich habe keine Ahnung, ob eine Ameise dazu gebracht werden könnte.

Während Stackoverflow so aussieht, wird es so sein Die Platz für alle Antworten, an dem niemand vorbeischaut http://www.javaranch.com für Java-Weisheit.Ich kann mir vorstellen, dass diese Frage dort schon vor langer Zeit behandelt wurde.

Es hängt davon ab, was Java 6 Funktionen, die Sie verwenden möchten. Für eine einfache Sache wie Zeile Sortierer zu JTables hinzufügen, können Sie testen, tatsächlich zur Laufzeit:

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
}

Dieser Code muss mit Java 6, kompiliert werden, sondern kann mit jeder Version (keine neue Klassen referenziert).

ausgeführt werden

EDIT: mehr korrekt zu sein, wird es seit 1.3 mit jeder Version arbeitet (nach diese Seite ).

Sie können alle tun Ihre ausschließlich auf Java6 kompiliert und dann System.getProperty verwenden ( „java.version“) bedingt entweder die Java5 oder den Java6 Codepfad ausgeführt werden.

können Sie haben Java6-only-Code in einer Klasse und die Klasse wird so lange auf Java5 als der Java6-only Codepfad nicht ausgeführt wird.

gut laufen

Dies ist ein Trick, der verwendet wird, Applets zu schreiben, die auf dem alten MSJVM der ganzen Weg bis zu brandneuer Java-Plug-in JVMs ausgeführt werden.

Es gibt keine Pre-Compiler in Java. Somit ist keine Möglichkeit, ein #ifdef wie in C zu tun Build-Skripte wäre der beste Weg sein.

Sie können bedingte Kompilierung, aber nicht sehr schön - javac wird unerreichbar Code ignorieren. Wenn Sie also Ihren Code richtig strukturiert, können Sie die Compiler bekommen Teile des Codes zu ignorieren. Um dies richtig zu nutzen, würden Sie auch die richtigen Argumente zu javac passieren müssen, damit es nicht unerreichbar Code als Fehler melden, und sich weigern, zu kompilieren: -)

Die öffentliche statische oben genannte Endlösung hat einen zusätzlichen Vorteil der Autor nicht erwähnt - wie ich es verstehe, wird der Compiler es bei der Kompilierung erkennen und beliebigen Code kompiliert aus, die innerhalb einer if-Anweisung ist, die auf das bezieht sich letzter Variable.

Also ich denke, das ist die genaue Lösung, die Sie suchen.

Eine einfache Lösung könnte sein:

  • Stellen Sie die unterschiedlichen Klassen außerhalb der normalen Classpath.
  • Schreiben Sie einen einfachen benutzerdefinierten Classloader und installieren Sie es in Haupt als Standard-.
  • Für alle Klassen außer den 5/6 denjenigen, kann der cassloader seiner Eltern (der normale System Classloader)
  • verschieben
  • Für die 5/6 diejenigen (die die Einzigen sein sollte, die nicht von den Eltern zu finden) kann entscheiden, welche über die 'os.name Eigentum oder einem Ihrer eigenen verwenden.

Sie können die Reflection-API verwenden. Setzen Sie alle Ihre 1.5-Code in einer Klasse und 1,6 api in einem anderen. In Ihrem Ant-Skript erstellen zwei ein Ziele für 1,5, die die 1,6-Klasse nicht kompiliert werden und einen für 1.6, die die Klasse 1.5 nicht kompiliert werden. in Ihrem Code überprüfen Sie Ihre Java-Version und laden Sie die entsprechende Klasse auf diese Weise javac nicht beschweren sich über fehlende Funktionen mithilfe von Reflektion. Dies ist, wie ich meine MRJ kompilieren (Mac Runtime für Java) Anwendungen unter Windows.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top