Java: пакет com.sun.java.swing.plaf.windows не существует

Я перешел с Java 8 на Java 17. Код теперь не компилируется

В частности, импорт из пакета com.sun.java.swing.plaf.windows теперь недействителен.

java: пакет com.sun.java.swing.plaf.windows не существует

Однако оно существует. Просто новый компилятор неразумен. Теперь он по какой-то причине отказывается признавать свое существование.

ошибка компиляции, com.sun.java.swing.plaf.windows не существует

Эти пакеты com.sun.java.swing никогда не предназначались для использования вне самой Java, и их не следовало использовать напрямую. Java теперь обеспечивает это.

Марк Роттевел

Хорошо, но мы все равно ссылаемся на пакет. Java утверждает, что обратно совместима, поэтому все, что разрешено в старой версии, должно быть разрешено и в более новой.

Так что же нам делать?

// MRE. Compilation fails. Amazon Corretto 17

package demos.button;

import com.sun.java.swing.plaf.windows.WindowsLookAndFeel;

import javax.swing.*;
import java.awt.*;

public class CheckBoxDemo {
    public static void main(String[] args) throws UnsupportedLookAndFeelException, ClassNotFoundException,
            InstantiationException, IllegalAccessException {
        // you don't expect us to pass strings directly, do you?
        UIManager.setLookAndFeel(WindowsLookAndFeel.class.getName());

        JFrame frame = new JFrame("Check Box demo");
        JPanel mainPanel = createMainPanel();
        frame.setContentPane(mainPanel);
        frame.setLocationRelativeTo(null);
        frame.pack();
        frame.setVisible(true);
    }

    private static JPanel createMainPanel() {
        FlowLayout layout = new FlowLayout();
        layout.setAlignment(FlowLayout.CENTER);
        JPanel mainPanel = new JPanel(layout);
        mainPanel.add(createCheckBox());
        return mainPanel;
    }

    private static JCheckBox createCheckBox() {
        JCheckBox checkBox = new JCheckBox();
        return checkBox;
    }
}

Даже если я отключу опцию --release, код все равно не компилируется. Например, потому что раньше ComboPopupgetList() выглядело вот так

public JList getList();

и сейчас это выглядит так

public JList<Object> getList();

Так что, если ваша реализация ComboPopup использовала какие-либо аргументы типа, не повезло.

// no longer compiles
@Override
public JList<T> getList() {
    return itemList;
}

На обратную совместимость это вообще не похоже. Разве не в этом (наряду с кроссплатформенной поддержкой) весь смысл Java?

Решение состоит в том, чтобы изменить ваш код так, чтобы он не использовал классы com.sun.java.swing.plaf.windows напрямую. В вашем примере не похоже, что для этого есть веская причина.

Stephen C 09.08.2024 08:31

Работать в Windows или Linux?

life888888 09.08.2024 08:32

«Java утверждает, что обратно совместима, поэтому все, что разрешено в старой версии, должно быть разрешено и в более новой». - >пожимаю плечами<. Со времени Java 8 произошло несколько кардинальных изменений. Если вас это останавливает, не обновляйтесь до Java 8.

Stephen C 09.08.2024 08:33

@StephenC, но это public, не так ли? Я смогу использовать что угодно public хорошо

Heneh 09.08.2024 08:44

@life888888 Windows 10

Heneh 09.08.2024 08:45

Критические изменения @StephenC — это нормально. С другой стороны, несовместимые обратно не являются

Heneh 09.08.2024 08:45

Большая часть com.sun.* была специфична для реализации Java от Sun (а позже и от Oracle) и не предназначалась для общего использования, поскольку на самом деле они не являются частью спецификации Java и, таким образом, могут измениться и исчезнуть при необходимости. Даже если они в настоящее время включены в ваш дистрибутив Java, они не экспортируются из модуля java.desktop (модульность была введена в Java 9), поскольку вам вообще не следовало использовать их напрямую. Вы можете попробовать добавить необходимый экспорт с помощью --add-exports в командной строке или Add-Exports в манифесте вашего приложения.

Mark Rotteveel 09.08.2024 08:56

Кстати, «Java утверждает, что она обратно совместима», да, но это действительно только для официального, поддерживаемого, общедоступного интерфейса («Пакеты java.*, javax.* и org.*, задокументированные в спецификации API Java Platform Standard Edition» )

user85421 09.08.2024 09:15

также проверьте Миграция с JDK 8 на более поздние версии JDK

user85421 09.08.2024 09:20

@user85421 user85421 Добавление экспорта на самом деле не обязательно, поскольку есть более эффективные способы сделать это (некоторые из них представлены в Java 9 специально по этой причине).

Mark Rotteveel 09.08.2024 09:24
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
10
77
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Его можно выбрать только в том случае, если система применима.

UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
Ответ принят как подходящий

Начиная с Java 9, Java является модульной, и вещи, которые вам не следует использовать, не экспортируются из этих модулей, включая общедоступные классы, которые не являются частью API, определенного спецификацией Java. Классы в com.sun.* в большинстве случаев относятся к реализации Java Sun/Oracle, а иногда даже зависят от платформы (как в случае с этим внешним видом), а не являются частью спецификации Java. По существу, они обычно считаются деталью реализации, а не частью какого-либо API, и, следовательно, на них не распространяются обещания Java по обратной совместимости. Если бы вы использовали реализацию Java от другого поставщика, у вас, скорее всего, не было бы к ним доступа.

Итак, начиная с Java 9, когда модули реализованы, вы больше не можете получить доступ к этим классам, даже если они все еще существуют (пакет com.sun.java.swing.plaf.windows находится в модуле java.desktop, по крайней мере, в сборках Windows). Теоретически вы все равно можете получить к ним доступ, если добавите необходимые экспорты (например, с помощью --add-exports в командной строке или с помощью Add-Exports в манифесте JAR приложения).

Однако гораздо проще заменить ваш код чем-то, что будет просто работать без экспорта, как это всегда рекомендовали Sun, а теперь и Oracle (например, см. учебник Swing Как настроить внешний вид, основанный на Ява 8).

У вас есть несколько вариантов:

  1. Явно задайте внешний вид по имени класса:

    UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
    

    Я бы не рекомендовал это, поскольку это по-прежнему привязывает вас к вариантам Java Oracle/OpenJDK.

  2. Используйте имя внешнего вида вместо имени класса (появившегося в Java 9):

    UIManager.setLookAndFeel(UIManager.createLookAndFeel("Windows");
    

    Обратите внимание, что в руководстве упоминаются имена Windows XP и Windows Vista, но на самом деле это Windows Classic и Windows. Могу только предположить, что когда эта функция была представлена ​​в Java 9, они посчитали имена, упомянутые в руководстве по Java 8, не подходящими для этого.

    Если реализация или платформа Java на самом деле не имеет указанного внешнего вида, это приведет к появлению UnsupportedLookAndFeelException.

  3. Сделайте его динамическим на основе реальной системы:

    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
    

Первый вариант всегда был лучшим решением, если вы хотели, чтобы пользовательский интерфейс выглядел как Windows. Я предполагаю, что Oracle заметил это и поэтому предоставил новый метод, который вы используете в варианте 2, я раньше его не видел. При необходимости можно использовать UIManager.getInstalledLookAndFeels() для поиска правильного L&F Windows.

Rob Spoor 09.08.2024 10:03

@RobSpoor Действительно, но это все еще специфично для реализаций Oracle/OpenJDK; третий вариант на самом деле самый гибкий ИМХО.

Mark Rotteveel 09.08.2024 10:04

Несмотря на то, что он наиболее гибкий, его пользовательский интерфейс сильно отличается от собственных приложений. Вот почему я упомянул метод getInstalledLookAndFeels(), его можно использовать для поиска правильного L&F Windows. Систему L&F можно использовать в качестве запасного варианта, если совпадений нет.

Rob Spoor 09.08.2024 11:47

@RobSpoor В Windows getSystemLookAndFeelClassName() также приведет к изменению внешнего вида Windows. Первый и второй варианты просто приведут к ошибке на платформах, которые не имеют внешнего вида Windows (это любая платформа, отличная от Windows, AFAIK).

Mark Rotteveel 09.08.2024 11:50

Вы абсолютно правы, я перепутал с getCrossPlatformLookAndFeelClassName().

Rob Spoor 09.08.2024 13:24

Другие вопросы по теме