Статический импорт Java завершается с ошибкой, когда импортируемый класс расширяет стороннюю библиотеку

Настройка проблемы состоит из трех java-библиотек (я убрал все имена пакетов для удобочитаемости, везде используются полные имена):

  1. external-lib: предоставляет абстрактный класс

    public abstract class AbstractExternal {}
    
  2. my-lib-A: предоставляет класс

    public class ClassA extends AbstractExternal {
        public static final String FOO = "foo";
    }
    

    external-lib находится в пути к классам my-lib-A.

  3. my-lib-B статически импортирует FOO из ClassA:

    import static ClassA.FOO;
    public class ClassB {
        private String foo = FOO;
    }
    

    my-lib-A находится в пути к классам my-lib-B, а external-lib — нет.

Проблема: Строка import static выдает следующую ошибку:

The type AbstractExternal cannot be resolved. It is indirectly referenced from required .class files.

Однако (1), при изменении ClassB на

import ClassA;
public class ClassB {
    private String foo = ClassA.FOO;
}

компилятор доволен.

Однако (2), при добавлении второй абстракции две my-lib-A вроде

public class AbstractClassA extends AbstractExternal {}

а также

public class ClassA extends AbstractClassA {
    public static final String FOO = "foo";
}

статический импорт ClassA.FOO в приведенном выше примере работает.

Вопрос 1: Почему import static ClassA.FOO не работает, а import ClassA с ClassA.FOO работает?

Вопрос 2: Почему import static ClassA.FOO работает, когда он расширяет другой класс из my-lib-A, который затем расширяет AbstractExternal?

Изменить: важная информация: речь идет о компиляторе компиляторе Eclipse. для Java (ECJ).

Редактировать 2: javac синхронизирован с ECJ и может скомпилировать обычный импорт и доступ к классу в ClassB, в то время как статический импорт терпит неудачу.


person Henning Treu    schedule 16.04.2018    source источник


Ответы (1)


Ecj в идеале «не должен» сообщать об этой ошибке. Я зарегистрировал ошибку 533890, чтобы отследить это.

Общая тема всех ошибок этого сообщения ("... не может быть разрешена. На него косвенно ссылаются...") — это конфликт между:

  1. желая полного семантического анализа, который знает обо всех соответствующих классах и
  2. требуется устойчивость, если путь сборки не содержит всех классов, от которых зависит текущий класс (косвенно).

Очевидно, что JLS не указывает, как компиляторы должны обрабатывать неполные пути сборки, но для удобства пользователей не следует сообщать об ошибках, если семантический анализ позволяет избежать изучения определенных косвенных зависимостей.

Где и когда этого действительно можно избежать, необходимо проверять (и реализовывать) в каждом конкретном случае, но данный пример, скорее всего, квалифицируется как случай, которого можно избежать.

Пока эта проблема не будет решена, ее можно избежать, сделав external-lib видимым также для my-lib-B (например, используя зависимость проекта). В модульных системах, таких как OSGi или JPMS, может быть хорошей идеей позволить my-lib-A "повторно экспортировать" свою зависимость external-lib, поскольку его класс API ClassA является "неполным" для клиентов, которые не могут видеть AbstractExternal.

person Stephan Herrmann    schedule 20.04.2018