web-dev-qa-db-ja.com

Java条件付きコンパイル:コードチャンクがコンパイルされないようにする方法?

私のプロジェクトでは、コンパイルと実行にJava 1.6が必要です。これで、Java 1.5(マーケティング側から)で動作する必要があります。メソッド本体を置き換えて(戻り値の型と引数は同じままにして)エラーなしでJava 1.5でコンパイルできるようにします。

詳細:すべてのOS固有のものをカプセル化するOSというユーティリティクラスがあります。メソッドがあります

_public static void openFile(Java.io.File file) throws Java.io.IOException {
  // open the file using Java.awt.Desktop
  ...
}
_

ダブルクリック(start Windowsコマンドまたはopen Mac OS Xコマンドに相当)を使用してファイルを開きます。 Java 1.5ではコンパイルできないため、コンパイル中に除外し、Windowsの場合は_run32dll_、Mac OS Xの場合は_Runtime.exec_を使用してopenを呼び出す別のメソッドに置き換えます。

質問:どうすればいいですか?注釈はここで役立ちますか?

注:antを使用し、Java 1.5の目的のコードを持つOSクラスを含む2つのJavaファイル_OS4J5.Java_および_OS4J6.Java_を作成できます。 1.6コンパイルする前にそれらの1つを_OS.Java_にコピーします(またはい方法-Javaバージョンに応じて条件付きで_OS.Java_の内容を置き換えます)。 、別の方法がある場合。

さらに詳しく:Cでは_ifdef, ifndef_を使用でき、Pythonではコンパイルがなく、hasattrまたは他の何かを使用して機能をチェックでき、Common LISPでは_#+feature_を使用できます。 Javaに似たようなものはありますか?

この投稿 が見つかりましたが、役に立たないようです。

どんな助けも大歓迎です。 kh。

47
khachik

いいえ、Javaの条件付きコンパイルはサポートされていません。

通常の計画は、アプリのOS固有のビットをInterfaceの背後に隠し、実行時にOSタイプを検出し、Class.forName(String)を使用して実装をロードすることです。

あなたの場合、両方をコンパイルできない理由はありませんOS*(およびアプリ全体のインファクト)Java 1.6 with -source 1.5 -target 1.5その後、OSクラス(現在はインターフェイスになる)を取得するためのファクトリメソッドで、Java.awt.Desktopクラスが利用可能であり、正しいバージョンをロードします。

何かのようなもの:

 public interface OS {
     void openFile(Java.io.File file) throws Java.io.IOException;
 }

 public class OSFactory {
     public static OS create(){
         try{
             Class.forName("Java.awt.Desktop");
             return new OSJ6();
         }catch(Exception e){
             //fall back
             return new OSJ5();
         }
     }
 }
42
Gareth Davis

Garethが提案したようなインターフェースの背後に2つの実装クラスを隠すのがおそらく最善の方法です。

ただし、antビルドスクリプトのreplaceタスクを使用して、一種の条件付きコンパイルを導入できます。秘Theは、ソースをコンパイルする直前に、テキストの置換によってオープン/クローズされるコメントをコード内で使用することです:

/*{{ Block visible when compiling for Java 6: IFDEF6

public static void openFile(Java.io.File file) throws Java.io.IOException {
  // open the file using Java.awt.Desktop
  ...

/*}} end of Java 6 code. */

/*{{ Block visible when compiling for Java 5: IFDEF5

  // open the file using alternative methods
  ...

/*}} end of Java 5 code. */

antでは、Java 6でコンパイルする場合、「IFDEF6」を「* /」に置き換えて、

/*{{ Block visible when compiling for Java 6: */

public static void openFile(Java.io.File file) throws Java.io.IOException {
  // open the file using Java.awt.Desktop
  ...

/*}} end of Java 6 code. */

/*{{ Block visible when compiling for Java 5, IFDEF5

public static void openFile(Java.io.File file) throws Java.io.IOException {
  // open the file using alternative methods
  ...

/*}} end of Java 5 code. */

また、Java 5)をコンパイルする場合は、「IFDEF5」を置き換えます。// comments/*{{ブロック内で/*}}を使用するよう注意する必要があることに注意してください。

17
rsp

以下に紹介するAntスクリプトは、すてきできれいなトリックを提供します。

リンク: https://weblogs.Java.net/blog/schaefa/archive/2005/01/how_to_do_condi.html

例では、

//[ifdef]
public byte[] getBytes(String parameterName)
        throws SQLException {
    ...
}
//[enddef]

antスクリプトを使用

        <filterset begintoken="//[" endtoken="]">
            <filter token="ifdef" value="${ifdef.token}"/>
            <filter token="enddef" value="${enddef.token}"/>
        </filterset>

詳細については上記のリンクにアクセスしてください。

7
Youngjae

リフレクションを使用して呼び出しを行い、Java 5でコードをコンパイルできます。

例えば.

Class clazz = Class.forName("Java.package.ClassNotFoundInJavav5");
Method method = clazz.getMethod("methodNotFoundInJava5", Class1.class);
method.invoke(args1);

例外をキャッチして、Java 5。

5
Peter Lawrey

Java 9では、マルチリリースjarファイルを作成できます。基本的に、同じJavaファイルの複数のバージョンを作成することを意味します。

それらをコンパイルするとき、必要なjdkバージョンでJavaファイルの各バージョンをコンパイルします。次に、次のような構造にパックする必要があります。

+ com
  + mypackage
    + Main.class
    + Utils.class
+ META-INF
  + versions
    + 9
      + com
        + mypackage
          + Utils.class

上記の例では、コードの主要部分はJava 8でコンパイルされますが、Java 9の場合、追加の(しかし異なる)バージョンがありますUtilsクラス。

このコードをJava 8 JVMで実行すると、META-INFフォルダー内のクラスもチェックしません。ただし、Java 9では、クラスのより新しいバージョンを見つけて使用します。

5
bvdb

私はそれほど素晴らしいJavaエキスパートではありませんが、Javaの条件付きコンパイルはサポートされており、簡単に実行できます。お読みください。

http://www.javapractices.com/topic/TopicAction.do?Id=64

要点を引用する:

条件付きコンパイルのプラクティスは、クラスのコンパイル済みバージョンからコードのチャンクをオプションで削除するために使用されます。コンパイラは、到達不能なコードの分岐を無視するという事実を使用します。条件付きコンパイルを実装するには、

  • 静的な最終的なブール値をあるクラスの非プライベートメンバーとして定義する
  • ブール値を評価するifブロックで条件付きでコンパイルされるコードを配置します
  • ブール値をfalseに設定すると、コンパイラーはifブロックを無視します。それ以外の場合は、値をtrueのままにします

もちろん、これにより、メソッド内のコードの塊を「コンパイル」できます。クラスメンバ、メソッド、またはクラス全体を削除する(スタブのみを残す場合もあります)には、プリプロセッサが必要です。

5
gregko

アプリケーションで条件付きで有効なコードブロックが必要ない場合は、プリプロセッサが唯一の方法です。mavenプロジェクトとantプロジェクトの両方に使用できる Java-comment-preprocessor を参照してください。
p.s。
また、私は ソースの重複なしでJEP-238マルチバージョンJARを構築するためにMavenでプリプロセスを使用する方法の例

4
Igor Maznitsa

Java from Manifold framework )の新しい Preprocessor があります。これはjavac プラグインこれは、直接がJavaコンパイラーと統合されていることを意味します。管理するビルド手順、コード生成ターゲットなどはありません。

enter image description here

1
Scott

Java Primitive Specializations Generator は条件付きコンパイルをサポートします:

   /* if Windows compilingFor */
   start();
   /* Elif Mac compilingFor */
   open();
   /* endif */

このツールにはMavenおよびGradleプラグインがあります。

0
leventov