Разрешить Eclipse распознавать исправленный модуль стандартной библиотеки JDK11

Просто из любопытства я пытаюсь настроить Eclipse, чтобы он мог скомпилировать и запустить приложение с исправленным классом стандартной библиотеки.

У меня есть 2 Java-проекта patch и consumer: один содержит класс исправления строки (с новым методом size(), идентичным length()), а другой должен использовать указанный метод size(). Установка следующая:

- patch
  - bin (contains class files)
  - src
    - java
      - lang
        - String.java

- consumer
  - src
    - consumer
      - Main.java
      - module-info.java

Основная.java:

package consumer;
public class Main {
    public static void main(String[] args) {
        String s  = new String("hello");
        System.out.println(s.size());
    }
}

После компиляции patch (тем самым получая String.class внутри patch/bin/java/lang/) я знаю, что могу легко использовать:

java --patch-module java.base=patchpjt/bin/  consumer/src/consumer/Main.java

Чтобы правильно вызвать вновь добавленный метод size(), получив результат 5.

Проблема в том, что в Eclipse метод size по-прежнему не распознается (ошибка заключается в том, что метод Size() недоопределен для типа String):

введите здесь описание изображения

Итак, мой вопрос:

  • Как настроить Eclipse, чтобы проект consumer корректно компилировался, запускался и не выдавал ошибок?
  • Как настроить Eclipse, чтобы в Content Assist отображался метод size()?

Я знаю, что мне нужно использовать Build Path -> Module Path -> Edit Is Modular -> Details Tab -> Patched module, но я не знаю, как настроить оба проекта.

Некоторая информация, которая может оказаться полезной:

  • Затмение 2018-12 (4.10.0) Идентификатор сборки: 20181214-0600

Спасибо за любой ответ.


person Koldar    schedule 11.01.2019    source источник
comment
Как вы настроили свой проект Eclipse, содержащий патч? У меня это работает только при попытке исправить модули, отличные от jdk, путем создания немодульного проекта, имеющего зависимость от модуля, который я хочу исправить, определенного в пути к классам, а не в пути к модулю. Однако для JRE Eclipse не позволяет мне добавить его в путь к классам... ну... он разрешает это, но затем каким-то образом решает снова переместить его в путь к модулям. Следовательно, я всегда получаю Пакет java.lang конфликтует с пакетом, доступным из другого модуля: java.base. Любые подсказки?   -  person Haasip Satang    schedule 27.01.2019


Ответы (1)


Вы используете --patch-module, для которого он не предназначен (JEP 261: Module System):

Опция --patch-module предназначена только для тестирования и отладки. Его использование в производственных условиях настоятельно не рекомендуется.

В вашем сценарии вы не исправляете существующий метод, а добавляете дополнительный метод, который нарушает работу API системной библиотеки. Eclipse поддерживает только исправление без нарушения API системной библиотеки. Тот факт, что javac не показывает никакой ошибки (вероятно, из-за отсутствия проверок, если API не будет сломан), на мой взгляд, является ошибкой.

Если вы создаете свою собственную JRE, добавьте ее в Окно > Настройки: Java > Установленные JRE и убедитесь, что при создании нового проекта Java выбрана не среда выполнения JRE, а вашей конкретной JRE.

person howlger    schedule 11.01.2019
comment
Спасибо за ваш ответ. Я следил за чем-то вроде это для добавления методов в библиотеку (в основном полезные методы в коллекциях типа List.firstOrFail()). Начиная с Java11, я задавался вопросом о модульной системе, как этого добиться, поскольку rt.jar больше не существует. Хочешь подкинуть идей (или просто стремно это делать)? - person Koldar; 15.01.2019
comment
Я предполагаю, что стоимость обслуживания для расширения стандартной библиотеки слишком высока. Вместо этого я бы разместил дополнительную функциональность в отдельных пакетах, классы и интерфейсы которых расширяют стандартные классы. Аналогично тому, что делает, например, Eclipse Collections. - person howlger; 15.01.2019
comment
@howlger: Хотя JEP говорит, что это не рекомендуется, я не смог найти ничего о том, что не поддерживается, потому что это нарушает API. На самом деле я даже не считаю добавление нового метода нарушением API. Удаление одного из них, безусловно, было бы и для меня также изменением существующего метода и изменением поведения. Поэтому я до сих пор не понимаю, почему вышеизложенное не должно поддерживаться для целей тестирования и отладки. Именно там (при тестировании) я мог бы попробовать, как работает новый метод. Или я что-то упускаю? - person Haasip Satang; 27.01.2019
comment
@HaasipSatang Если вы добавите метод в класс системной библиотеки и используете его в своем приложении, приложение больше не сможет работать с немодифицированной JRE. С точки зрения системной библиотеки, API был расширен, но если приложение использует расширение, оно больше не привязано к заданному API (именно это я имел в виду, говоря, что оно нарушает работу API). Если вы хотите изменить системную библиотеку, вы не должны смешивать ее с кодом приложения. Идея --patch-module, как следует из названия, заключается в исправлении, а не в расширении системной библиотеки. - person howlger; 28.01.2019
comment
@howlger Хорошо, я понимаю, откуда ты. Но допустим, вы хотите добиться того, что можно было бы легко сделать с помощью -Xbootclasspath/p в выпусках, предшествующих JDK 9. Поэтому, если вам нужно перенести проект, который расширил базовые классы и полагался на эту функциональность, я считаю, что это нормально. В моем случае само приложение не знает модифицированных системных классов (поэтому здесь нет риска что-то сломать), но агент, поставляемый вместе с измененными классами, зависит от этих модификаций. Другой альтернативой может быть BCI, хотя и более сложный. - person Haasip Satang; 28.01.2019
comment
Как вы создали банку патчей? Хотя мне удается создавать проекты для исправления модулей, отличных от jdk (путем определения зависимости от модуля, который должен быть исправлен в пути к классам, а не в пути к модулям), у меня возникают проблемы с тем, чтобы Eclipse позволял мне переопределять классы из java.base без жалоб что пакет конфликтует с уже определенным там пакетом. Итак, как вы настроили свой проект, чтобы разрешить переопределение java.net.URLClassLoader? Примечание: проблема не в использовании jar, а в его компиляции. - person Haasip Satang; 28.01.2019
comment
@HaasipSatang В диалоге, который показан здесь как второй (под)диалог, я проверил Исправляет существующий модуль и ввел java.base, чтобы протестировать исправление и создать JAR-файл исправления. ИМХО расширения должны разрабатываться как отдельные фреймворки вне системной библиотеки и не нарушать инкапсуляцию существующего модуля. - person howlger; 28.01.2019
comment
@howlger: это сработало, спасибо. Теперь, как и в исходном вопросе, Eclipse жалуется, что не может разрешить некоторые дополнительные зависимости, которые я добавляю в исправленном модуле. Таким образом, отображается ошибка, завершение кода нельзя использовать, но полученный код компилируется и может использоваться. На мой взгляд довольно странно. Я бы не ожидал, что Eclipse будет более ограничивающим, чем спецификация. Итак, все, что работает с java и javac, должно работать с Eclipse IMHO. Спасибо еще раз. - person Haasip Satang; 28.01.2019
comment
@HaasipSatang Что правильно, а что неправильно, определяется Спецификациями языка Java и виртуальной машины а не реализацией java и javac (см. например, здесь). Сам Eclipse основан на OSGi и поддерживает в модуляризации вещи, которые хорошо работали более десяти лет (например, это ограничение из-за этого ). Поскольку JPMS нельзя комбинировать с OSGi и поскольку JPMS не поддерживает OSGi, сам Eclipse останется основанным на OSGi. - person howlger; 28.01.2019
comment
@howlger Извини, теперь ты потерял меня. Да, конечно, я имел в виду спецификацию, а не только реализацию. Но возвращаясь к нашей конкретной проблеме, я не нашел нигде в спецификации того, что вещи, которые вы считаете нарушающими API (например, добавление новых методов в патч), запрещены. Мы можем спорить о том, хорошо это или нет, но, насколько мне известно, это по крайней мере поддерживается, не так ли? Поэтому, по моему мнению, Eclipse не должен не помечать эти исправления как невозможно разрешить и т. д., хотя на самом деле это работает и не запрещено. Или я что-то пропустил в спецификации или JEP, говоря, что это будет ошибка? - person Haasip Satang; 29.01.2019
comment
@HaasipSatang JEP 261 говорит, что предназначен только для тестирования и отладки. С моей точки зрения, тестирование и отладка исключают изменение Java API. Добавление метода через --patch-module и его использование выглядит для меня хаком. Что, если патч содержит класс, из которого удален внутренний класс? Если вы разрешаете добавлять вещи, удаление также должно быть возможным. Но держу пари, это не сработает. - person howlger; 29.01.2019
comment
@howlger да, вы не можете удалить такие вещи, как внутренние классы. Но это также было невозможно в прошлом, то есть до Java 9. Используя параметр -Xbootclasspath, вы могли добавлять или добавлять свои собственные классы, но вы не могли удалить то, что уже есть. А зачем вам что-то удалять? В конце концов, большинство таких изменений должны ввести новое поведение, поэтому, если вы не хотите, чтобы определенный класс больше использовался, вам нужно будет переопределить/исправить все, что он использует. Тем не менее, класс removed по-прежнему будет доступен в пути к классам, просто не будет использоваться. Так что не вижу проблемы. - person Haasip Satang; 31.01.2019
comment
В конце концов, я просто ищу способ добиться чего-то подобного тому, что я мог бы сделать с -Xbootclasspath/p. Например. Я хочу добавить поле в определенный класс (скажем, java.lang.ClassLoader) и использовать его во всех его подклассах и, возможно, в другом месте. Удалось ли скомпилировать этот патч, так как подклассы жалуются, что они не в поле. Без зависимостей моих пропатченных классов между собой все работает (кроме Eclipse, подсвечивающего все красным). Любая идея, что нужно добавить/настроить, чтобы подклассы могли видеть новые поля? - person Haasip Satang; 31.01.2019
comment
@HaasipSatang Ничего не удалялось до Java 9, поэтому это не требовалось, но это изменилось. Но, конечно же, вы можете создать свою собственную JRE и добавить ее в Window › Preferences: Java › Installed JREs. При создании нового проекта Java убедитесь, что выбранная вами JRE выбрана как конкретная JRE (вместо выбора среды выполнения JRE). Я не знаю, как создать пользовательскую JRE. jlink не поддерживает --patch-module, что означает, что это официально не поддерживается. - person howlger; 01.02.2019
comment
@howlger Я не знаю, как создать пользовательскую JRE, кроме компиляции моей собственной версии JDK (что кажется большим накладным расходом по сравнению с исправлением и тем, что было возможно в прошлом). У меня было еще несколько проблем с исправлением java.base, но это было связано с изменениями компилятора, сделанными с помощью JEP280. Текущее поведение в Eclipse для меня однозначно баг, иногда компилируется (после очистки), иногда нет и т.д. Открыл один здесь - person Haasip Satang; 13.02.2019