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.

答案是你不能使用它……或者编译一个使用它的类……在 Java 的 Linux 版本上。该类不包含在rt.jarJava 的 Linux 版本的文件中。

此外,您应该使用它。Java 文档非常清楚地表明应用程序代码不应使用sun.*包层次结构中的类。


如果您别无选择,只能这样做,那么最好的办法是使用反射来获取该w32Id字段的值。您还需要处理media对象不是Win32MediaTray类实例的情况。请注意,您依赖于 Oracle 明确表示您不应该依赖的实现细节。它们有可能在未来的某些 Windows 版本中发生更改(恕不另行通知!)。

其他选择是:

  • 为每个平台实现一个不同的平台适配器类。这些必须在每个平台上单独编译,然后动态加载。

  • 为每个平台实现单独的代码库。

于 2013-10-05T14:26:45.863 回答
1

为了让编译器满意,您可以实现一个名为的虚拟类sun.print.Win32MediaTray,并使其在编译和运行时类路径中都可用。该类不需要工作,它只需要与 API 兼容(相同的签名和返回类型,但在这种情况下你只需要扩展Media并拥有一个public int winID),这样你就可以同时满足编译器和验证器的要求。

在运行时,rt.jar由于加载委托,应该在 Windows 上加载包含的版本。在 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 回答
0

将使用 Windows 特定内容的代码放入单独的 jar 中怎么样?然后您可以在 Windows 上编译并包含该 jar,否则将其保留在系统之外。

一种标准方法是让您的应用程序代码使用一个或多个接口;您可以让工厂提供实现类或使用 Spring 或其他方式注入它们。但我认为,您的问题应该是“我在一个针对多个操作系统的应用程序中有这种 Windows 依赖项,我该如何处理它?”而不是“我如何在 Linux 上编译它”。

于 2013-10-05T14:43:47.197 回答