Что эквивалентно Java 9+ для удаления класса из AppContext; необходимо перезагрузить класс PrintServiceLookup - PullRequest
0 голосов
/ 19 марта 2020

Я перенес старый код API принтера в Java 8, и появляется следующее предупреждение:

Ограничение доступа: метод AppContext.getAppContext () 'не является API (ограничение для необходимой библиотеки 'C: \ Program Files \ Java \ jre1.8.0_51 \ lib \ rt.jar')

Это связано с этим кодом (изначально был получен из этого SO вопроса ):

/**
 * 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 загружает список видимых принтеров при загрузке в класс, но, по-видимому, не обновляет sh этот список или не имеет возможности вызвать обновление sh. Путь для продолжительного приложения, чтобы обновить sh список, состоял бы в том, чтобы либо выгрузить класс, как это делает код, либо перезапустить сам.

Мягкое исследование показывает, что предупреждение пришло Java 9, AppContext.getAppContext() будет недоступно. Без дальнейших исследований моя текущая идея исправления состоит в том, чтобы использовать доступный загрузчик классов для загрузки этого класса и очистки загрузчика классов при вызове этого метода.

В конечном счете, я хочу знать, что мне нужно сделать, чтобы правильно заменить это , В настоящее время работает на Windows, может перемещаться на Linux; Я вижу много обновлений этого SO вопроса относительно реализации Linux.

1 Ответ

1 голос
/ 19 марта 2020

PrintServiceLookupProvider (единственная конкретная реализация PrintServiceLookup) предоставляет поток, который должен это делать.

Он бесконечно проверяет наличие изменений и вызывает 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)

...