1

I encountered a compilation issue under Linux. I'm compiling java programs on Linux; the target use is both Linux and Windows. The code check if in there are platform specific classes (as shown in the code below). So if the code is running under Linux, the specific Windows code will not be executed.

The issue arise on the use of a platform specific class Win32MediaTray

The compile error reported is

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

Is it possible to compile it under Linux? Or is it just impossible? I can use some workaround (reflection?) Needless to say that the compilation under Windows gives no errors.

Thankyou for your help.

For reference, the code behind this issue is the following:

 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;
}
5
  • 1
    Tell us what your error is. I can guess, but don't want to waste my time. Commented Oct 5, 2013 at 14:00
  • 1
    Even if you can get it to compile, how would you expect it to run? It's a Windows-specific API... Commented Oct 5, 2013 at 14:19
  • 1
    @rcook "don't want to waste my time" Good one. I've seen a slew of questions recently reduced to 'noise' by people trying to guess answers. Commented Oct 5, 2013 at 14:20
  • @JonSkeet On the basis that 'information is better than speculation', I'd like to hear the answer to that as well. OTOH (my speculation), it could be that the OP is coding an app. that uses different behavior on different platforms (e.g. 'If Windows, put it in the media tray..'). Commented Oct 5, 2013 at 14:22
  • Thank you guys for your comments. I hope now the question is a better question Commented Oct 5, 2013 at 14:27

3 Answers 3

1

I believe that the class you are trying to use is sun.print.Win32MediaTray.

And the answer is that you cannot use it ... or compile a class that uses it ... on a Linux release of Java. That class is not included in the rt.jar file on a Linux release of Java.

Furthermore, you shouldn't be using it. The Java documentation makes it very clear that application code should not make use of classes in the sun.* package hierarchy.


If you have no choice but to do this, then your best bet is to use reflection to fetch the value of that w32Id field. You'll also need to deal with the case where the media object is not an instance of the Win32MediaTray class. Beware that you are relying on implementation details that Oracle says specifically that you shouldn't. There is a risk that they will change (without notice!) in some future Windows release.

The other alternatives are:

  • Implement your own platform adapter classes with a different one for each platform. These have to be compiled separately on each platform, and then dynamically loaded.

  • Implement separate codebases for each platform.

Sign up to request clarification or add additional context in comments.

1 Comment

I know I shouldn't be using this package. Right now this code is the only working code (after an extend research) to successfully programmatically select a printer tray for a print job. Please, if you are aware of a better way to achieve this, without using sun.*, let me know.
1

To make the compiler happy you could implement a dummy class named sun.print.Win32MediaTray and make it available both on the compile and runtime classpath. The class doesn't need to work, it only has to be API compatible (same signatures and return types, but in this case you only really need to extend Media and have a public int winID), so that you can satisfy both the compiler and the verifier.

At runtime, the version included in rt.jar should be loaded on Windows thanks to loading delegation. On Linux, the dummy version is the only one available, but you stated that the program checks for the platform and executes another branch of code, so it shouldn't cause your program to fail.

For example, with the following class on the classpath:

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

I managed to run this program on 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 );
        }
      }
    }
  }
}

The message in the static initializer is not printed on Windows, because the definition that is actually loaded is the one from rt.jar. Obviously, the code can be compiled on any platform.

1 Comment

Interesting idea, how to craft such class? At last I did it with reflection
0

How about putting the code that uses windows-specific stuff into a separate jar; then you can compile and include that jar on windows, and leave it off systems otherwise.

One standard way to do this is to have one or more interfaces used by your application code; you can have a factory provide the implementing classes or inject them with Spring or whatever. But I think rather than "how can I compile this on Linux" your question should be "I have this Windows dependency in an app targeted at multiple operating systems, how do I handle it?"

4 Comments

Adding another jar/interface/implementation would be a too heavy solution. I'd go for the reflection way.
Just how is this a "heavier" solution than using reflection?
It is heavier because I need to fork the build chain between Linux and Windows. Add a new jar/project. Use it from another jar/project. Detect when to use the jar
Well, of course you decide for yourself what the easier/better solution is. Whether this solution really is easier depends on just what you have to do with reflection, and we don't know that from this question, don't need to. But if you're taking on java reflection (or ANY major technology) because your build tool makes an easier solution more difficult, then you should consider whether you have the right build tool.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.