0

Linux でコンパイルの問題が発生しました。Linux で Java プログラムをコンパイルしています。対象は Linux と Windows の両方です。このコードは、プラットフォーム固有のクラスがあるかどうかをチェックします (以下のコードを参照)。そのため、コードが Linux で実行されている場合、特定の Windows コードは実行されません。

この問題は、プラットフォーム固有のクラスWin32MediaTrayの使用で発生します

報告されたコンパイルエラーは

PrinterScanner.java:9: error: cannot find symbol
import sun.print.Win32MediaTray;
                 ^

Linuxでコンパイルできますか? それとも不可能ですか?Windows でのコンパイルでエラーが発生しないことは言うまでもありません。

ご協力ありがとうございました。

参考までに、この問題の背後にあるコードは次のとおりです。

 private String getTrayName(Media media) {

    String result = "id:" + media.getValue();
    boolean isWin32 = media.getClass().getName().equals("sun.print.Win32MediaTray");
    if (isWin32) {
        Win32MediaTray w32 = (Win32MediaTray) media;
        result = result + ",winId:" + w32.winID;
    }
    return result;
}
4

3 に答える 3

1

コンパイラを満足させるには、という名前のダミー クラスを実装sun.print.Win32MediaTrayし、コンパイルと実行時のクラスパスの両方で利用できるようにすることができます。クラスは機能する必要はありません。コンパイラと検証者の両方を満たすことができるように、 API 互換性があればよいだけです (シグネチャと戻り値の型は同じですが、この場合、拡張Mediaして を持つだけで十分です)。public int winID

委任の読み込みにより、実行時に に含まれるバージョンがrt.jarWindows に読み込まれます。Linux では、ダミー バージョンしか利用できませんが、プログラムがプラットフォームをチェックし、コードの別のブランチを実行するため、プログラムが失敗することはないと述べました。

たとえば、クラスパスに次のクラスがあるとします。

package sun.print;

import javax.print.attribute.standard.Media;

public class Win32MediaTray extends Media {
  public int winID = 0xBADC0DE;
  protected Win32MediaTray(int value) {
    super(value);
  }
  static {
    System.out.println("Won't see me on Windows");
  }
}

Windowsでこのプログラムを実行することができました:

public class Main {
  public static void main(String[] args) {
    PrintService[] services = PrintServiceLookup.lookupPrintServices(null, null);
    for  (PrintService svc : services ) {
      DocFlavor flavor = DocFlavor.SERVICE_FORMATTED.PAGEABLE;
      Object o = svc.getSupportedAttributeValues(Media.class, flavor, null);
      if (o != null && o.getClass().isArray()) {
        for (Media media : (Media[]) o) {
          if ( media instanceof Win32MediaTray )
            System.out.println( ((Win32MediaTray) media).winID );
        }
      }
    }
  }
}

実際にロードされる定義は からのものであるため、静的初期化子のメッセージは Windows では出力されませんrt.jar。明らかに、コードはどのプラットフォームでもコンパイルできます。

于 2013-10-05T15:00:10.663 に答える
1

あなたが使おうとしているクラスはsun.print.Win32MediaTray.

その答えは、Java の Linux リリースでは使用できない、またはそれを使用するクラスをコンパイルできないということです。そのクラスはrt.jar、Java の Linux リリースのファイルには含まれていません。

さらに、あなたはそれを使うべきではありませんsun.*Java のドキュメントでは、アプリケーション コードでパッケージ階層内のクラスを使用してはならないことが明確に示されています。


これを行うしかない場合は、リフレクションを使用してそのw32Idフィールドの値を取得することをお勧めします。オブジェクトがクラスmediaのインスタンスでない場合にも対処する必要があります。Win32MediaTrayオラクルが特にそうすべきではないと言っている実装の詳細に依存していることに注意してください。これらは、将来の Windows リリースで (予告なしに!) 変更されるリスクがあります。

他の選択肢は次のとおりです。

  • プラットフォームごとに異なる独自のプラットフォーム アダプター クラスを実装します。これらは、プラットフォームごとに個別にコンパイルしてから、動的にロードする必要があります。

  • プラットフォームごとに個別のコードベースを実装します。

于 2013-10-05T14:26:45.863 に答える
0

Windows固有のものを使用するコードを別のjarに入れるのはどうですか。次に、そのjarをコンパイルしてWindowsに含めることができます。それ以外の場合は、システムから離れたままにします。

これを行う標準的な方法の 1 つは、アプリケーション コードで使用する 1 つまたは複数のインターフェイスを用意することです。ファクトリに実装クラスを提供させるか、Spring などでそれらを注入することができます。しかし、「これを Linux でコンパイルするにはどうすればよいか」というよりも、「複数のオペレーティング システムを対象とするアプリにこの Windows 依存関係があります。どうすればそれを処理できますか?」という質問が必要だと思います。

于 2013-10-05T14:43:47.197 に答える