1

I migrated older printer API code to Java 8, and the following warning appears:

Access restriction: The method 'AppContext.getAppContext()' is not API (restriction on required library 'C:\Program Files\Java\jre1.8.0_51\lib\rt.jar')

It is due to this code (originally sourced from this SO question):

/**
 * Printer list does not refresh itself; need to run this to refresh if necessary.
 */
public static void refreshSystemPrinterList() {

    Class[] classes = PrintServiceLookup.class.getDeclaredClasses();

    for (int i = 0; i < classes.length; i++) {

        if ("javax.print.PrintServiceLookup$Services".equals(classes[i].getName())) {

            AppContext.getAppContext().remove(classes[i]);  // the line that throws the warning
            break;
        }
    }

As I understand it, PrintServiceLookup loads a list of visible printers when it is classloaded, but it apparently does not refresh this list, or have the ability trigger a refresh. The way for a long-running application to refresh the list would be to either unload the class, which is what the code is doing, or restart itself.

Mild research on the warning reveals come Java 9, AppContext.getAppContext() will be inaccessible. Without further research, my current remediation idea is to use an accessible classloader for loading this class, and purging the classloader when this method is called.

Ultimately, I want to know what I need to do to properly replace this. Currently running on Windows, may be moving to Linux ; I see a lot of updates to this SO question regarding the Linux implementation.

JoshDM
  • 4,939
  • 7
  • 43
  • 72
  • Do you want to replace it or do you only care about supporting Java 9? You can support it without changing anything, by adding this command line option `--add-exports=java.desktop/sun.awt=ALL-UNNAMED` – Michael Mar 19 '20 at 19:21
  • 1
    @Michael of course, this option only helps as long as this class exists... – Holger Mar 20 '20 at 11:18

1 Answers1

1

PrintServiceLookupProvider (the only concrete implementation of PrintServiceLookup provides a thread that is supposed to do this.

It loops infinitely checking for changes, and calls refreshServices if there is one.

class PrinterChangeListener implements Runnable {
    long chgObj;
    PrinterChangeListener() {
        chgObj = notifyFirstPrinterChange(null);
    }

    @Override
    public void run() {
        if (chgObj != -1) {
            while (true) {
                // wait for configuration to change
                if (notifyPrinterChange(chgObj) != 0) {
                    try {
                        refreshServices();
                    } catch (SecurityException se) {
                        break;
                    }
                } else {
                    notifyClosePrinterChange(chgObj);
                    break;
                }
            }
        }
    }
}

Started here:

Thread thr = new Thread(null, new PrinterChangeListener(), "PrinterListener", 0, false);
thr.setDaemon(true);
thr.start();

If you are having problems with this not working, you should look into why notifyPrinterChange is not indicating that something changed. It's a native method, so the implementation will depend on your OS.

Unfortunately you cannot even use reflection to call refreshServices manually, since reflection over Sun modules is restricted (you can override it, but if you were doing that then you may as well override the export of AppContext)

Michael
  • 41,989
  • 11
  • 82
  • 128
  • 2
    In fact, the OP did not acknowledge that this problem exists at all. He's just migrating code containing a work-around stemming from times when the problem might have existed. – Holger Mar 20 '20 at 11:20
  • @Michael - What package is `PrintServiceLookupProvider` class? – JoshDM Mar 30 '21 at 20:51
  • 1
    @JoshDM `javax.print` https://docs.oracle.com/javase/8/docs/api/javax/print/PrintServiceLookup.html – Michael Mar 30 '21 at 20:53
  • 1
    @JoshDM oh sorry. the provider is `sun.print` https://github.com/openjdk/jdk/blob/master/src/java.desktop/unix/classes/sun/print/PrintServiceLookupProvider.java – Michael Mar 30 '21 at 20:56