有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

打印用于从AppContext中删除类的Java 9+等价物;需要重新加载PrintServiceLookup类

我已将较旧的打印机API代码迁移到Java 8,并出现以下警告:

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

这是由于该代码(最初来源于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;
        }
    }

据我所知,PrintServiceLookup在类加载时加载一个可见打印机列表,但它显然不会刷新此列表,或者能够触发刷新。长时间运行的应用程序刷新列表的方法是卸载类(代码就是这样做的),或者重新启动自身

对警告的温和研究表明,如果Java 9,AppContext.getAppContext()将无法访问。在没有进一步研究的情况下,我目前的补救想法是使用可访问的类加载器加载此类,并在调用此方法时清除类加载器

最终,我想知道我需要做些什么来正确地替换它。当前运行在Windows上,可能正在迁移到Linux;我看到很多关于Linux实现的更新


共 (1) 个答案

  1. # 1 楼答案

    ^{}^{}的唯一具体实现)提供了一个线程来实现这一点

    它无限循环检查更改,如果有更改,则调用refreshServices

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

    从这里开始:

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

    如果你对此不起作用有问题,你应该调查一下为什么notifyPrinterChange没有表明某些事情发生了变化。这是一种本机方法,因此实现将取决于您的操作系统

    不幸的是,您甚至不能使用反射来手动调用refreshServices,因为Sun模块上的反射受到限制(您可以覆盖它,但如果您这样做,那么您也可以覆盖AppContext的导出)