6 просмотров
Рейтинг статьи
1 звезда2 звезды3 звезды4 звезды5 звезд
Загрузка...

Записки о миграции на Java 10

OtherMedia

Информация должна принадлежать людям

Записки о миграции на Java 10

О том, какие разновидности боли ждут нас, можно узнать под катом.

Я просто оставлю это здесь не преследую цели изложить здесь все возможные проблемы с миграцией java-проектов с 8-й версии Java на 9-ю или 10-ю. Хочется зафиксировать свой небольшой опыт первого контакта с новыми версиями Java как-то кроме как в устных обсуждениях с коллегами. Возможно он кого-то остановит кому-то окажется полезен.

Для начала, IDEA версии 2018.1 отказалась работать на JVM версий 9 и 10 причём на 2-х разных машинах. Выглядело это как отсутствие части элементов GUI и отсутствие темы для части из оставшихся элементов. Это было небольшой проблемой, так как IDEA можно указать конкретную JVM для запуска.

1. Проблемы с реализацией модульности

Для начала давайте сделаем наше приложение модульным (не зря же разработчики JDK старались и страдали над проектом Jigsaw)?

1.1. Проблемы с утилитой jdeps

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

  • написать 1 или несколько файлов module-info.java с указанием в них имен модулей, зависимостей и экспортируемых пакетов
  • добавить аргументы для компилятора (—module-path и прочие)

Вроде бы выглядит всё довольно просто на первый взгляд.

1.1.1. Зависимости от внешних библиотек больше не работают без специальных заклинаний

Ничего просто не соберётся. Если вы хотите собрать модульно приложенье, то ваши зависимости также должны быть модульны. Иначе просто не получится добавить их в module-info.java. Точнее добавить-то можно — старомодные jar-файлы библиотек рассматриваются как так называемые «автоматические модули». Однако, проблема в том, что автоматические модули при сборке использовать нельзя. Да, в популярных репозиториях пока что очень мало библиотек, собраных в качестве модулей и вы просто не сможете их использовать. Nobody cares.

Здесь-то и понадобилась утилита jdeps, которая может проанализировать jar-файл и сгенерировать module-info.java для него, чтобы сделать из старомодного jar модуль. В качестве костыля workaround было решено просто взять и уйти распаковать все зависимости в одну кучку и сделать единый jar из которого можно попытаться сделать модный модуль-со-всеми-зависимостями. Пример на stackoverflow прилагается.

1.1.2. Потребуется включить значительно больше зависимостей, чем реально требуется

Jdeps разрешает зависимости рекурсивно, причём требует обязательного разрешения даже зависимостей, которые Maven/Gradle считают необязательными (optional). В итоге дерево зависимостей даже небольшого подопытного проекта разрастается в несколько раз. А модуль с зависимостями, который было решено изготовить в пункте (1.1.1) выкачивает пол интернета становится весьма тяжеловесным. Пример изложения сей боли здесь. Неожиданно обнаруживается, что log4j требует AWT, OSGI, ZeroMQ, Kafka или ещё что-нибудь в этом духе.

1.1.3. Неожиданный публичный [Роскомнадзор] утилиты

Обнаружилось, что в ситуации, когда некоторые классы дублируются в разных модулях, jdeps вываливается со стэктрэйсом IllegalStateException откуда-то из пучин своего кода без всякого пояснения что же пошло не так. Только одна маленькая зацепочка — сообщение «dependency on self» в качестве аргумента конструктора исключения. В какой-то момент мне показалось, что сие безобразие как бы намекало на то, что вообще всё (классы приложения, классы зависимостей, классы «необязательных» зависимостей) нужно свалить в один jar-файл. И действительно — сработало.

Читать еще:  Книга «Программирование без дураков»

1.2. Проблемы с runtime

Даже когда всё уже чудесным образом собралось, модульно приложенье и даже custom образ JRE к нему, оказалось, что самые главные сюрпризы — ещё впереди. То есть в runtime.

1.2.1. Теперь невозможно определить путь стартовому файлу/каталогу

В приложения Java зачастую есть необходимость определить путь к каталогу, где сидит фазан лежит jar-файл, из которого произошёл запуск приложения (например jar-файл, содержащий точку входа). Это обычно нужно, чтобы понять, где искать файлы приложения — конфигурацию, плагины и т.п. Такие вещи, как правило лежат по соседству (что весьма логично). Для определения этого пути обычно помогает заклинание вида:

Каково же было моё удивление, когда я обнаружил, что в новых версиях Java это заклинание более не работает и я вижу вместо пути к файлу что-то вроде «jrt://com.example.myapp». Я начал лихорадочно гуглить и переполнять стэк. Пробовал определять модуль и как-то выяснить, какие файлы к нему относятся. Попытки обращения к classpath тоже привели меня ни к чему, так как модульно приложенье запускается с так называемым module path заместо старомодного classpath. Это был финиш. Именно в этот момент я решил сворачивать свой эксперимент по переезду на Java 10. Нет, конечно можно было бы путь к каталогу передавать в командной строке или принудить пользователя запускать только из правильной директории. Но я для себя лично решил, что с меня пока что хватит.

1.2.2. Провал при попытке определения MIME-типа файла.

Оказалось, что вишенка на торте была не одна. Для экспериментов с десяткой я установил её и настроил в качестве JVM по умолчанию в системе. Поэтому сюрпризы продолжились. Код вроде

начал приводить к тому, что возвращался null в случае, если аргумент представлял из себя обычный CSV-файл с соответсвующим расширением. «Как же так?» — подумал я, «неужели JVM не в состоянии определить MIME-тип для обычного CSV-файла?». Я немного подебажил и обнаружил, что вызов вида

совершенно нагло кидает маловнятное исключение с сообщением вроде «malformed input».
Глубже в причинах этого безобразия я разбираться пока не стал. Лишь проверил файл /etc/mime.types — кракозябры не обнаружены вроде бы нормальный текстовый файл. То есть, JVM не смогла прочитать строки из текстового файла.

1.2.3. Нерабочий новый механизм Service Providers

Начиная с версии 9 Java также предлагает новый механизм Service Providers взамен старого. Вещь неплохая, позволяет делать плагины, которые разрешаются в runtime. Новый механизм подразумевает объявление расширения в module-info.java с помощью ключевых слов «provides» и «with». Казалось бы, что может быть проще. На практике это не заработало, в отличие от старого механизма (использующего файлы resources/META-INF/services/…). Разбираться, в чём проблема времени не хватило. Однако отметку о том, что без специальных заклинаний не взлетает, я пожалуй, тут сделаю.

2. Размышления о реализации local variable type inference

В случае с local variable type inference мы имеем новое ключевое слово «var» (variable, переменная), что намекает на влияние Scala. Однако лично мне показалось странным, почему не добавили также «val» (value, значение). Вместо этого приходится писать «final var», что читается глазами как «окончательная переменная» или даже как «постоянная переменная» — а это не только менее лаконично, но и как-то слегка противоречиво, на мой, привыкший к хорошему взгляд.

Читать еще:  Имя события проблемы startuprepairoffline что делать?

Также обнаружились довольно забавные вещи. Например:

Здесь JVM «запоминает» за именем «someStrings» тип ArrayList . Иногда, при полной луне умной подсветке синтаксиса можно увидеть предупреждение, что тип константы избыточен, а в Java принято использовать в этом месте интерфейсы, например List или даже Collection . Этого предупреждения от шибко умного редактора можно избежать, объявив константу так: Этот тип избыточен, так как принято использовать минимально необходимый интерфейс для уменьшения потенциальной связности (чтобы никто потом не стал дёргать за ArrayList-специфичные методы, например). Local variable type inference нарушает этот принцип. Этого можно избежать следующим способом:

но это уже выглядит как-то не очень лаконично. Этот момент не претендует на звание какого-то фатального недостатка, но демонстрирует лёгкий налёт противоречивости.

3. Неутешительные выводы

Некоторые из озвученных в этой записке проблем, возникли ещё в 9-й версии. Учитывая, что они так и не были пофиксеты до сих пор, есть неприятное ощущение, что весь этот бардак будет и в 11-й версии и даже далее. Не хотелось бы кликушествовать, но из этого субъективного ощущения вытекает другое: Java, как язык программирования, начинает переживать свой упадок. Возможно я не прав, а возможно так и есть и тогда на смену Java нужно искать другой инструмент.

ITnan

Все публикации Хабрахабр и Гиктаймс в одном месте
Выбран стиль: blue


API, ради которых наконец-то стоит обновиться с Java 8. Часть 2 +36

  • 09.02.20 13:34 •
  • orionll •
  • #487636 •
  • Хабрахабр •
  • 41
  • 12000

API, ради которых наконец-то стоит обновиться с Java 8. Часть 1 +42

  • 28.01.20 04:28 •
  • orionll •
  • #485750 •
  • Хабрахабр •
  • 40
  • 11500

Как Java 10 изменяет способ использования анонимных внутренних классов +10

  • 13.06.19 14:21 •
  • MaxRokatansky •
  • #456010 •
  • Хабрахабр •
  • Перевод
  • 5
  • 3600

Записки о миграции на Java 10 +20

  • 23.04.18 11:00 •
  • akurilov •
  • #354114 •
  • Хабрахабр •
  • 44
  • 8400

Java 10 General Availability +55

  • 21.03.18 10:32 •
  • olegchir •
  • #351694 •
  • Хабрахабр •
  • 78
  • 17400

Что там с JEP-303 или изобретаем invokedynamic +31

  • 10.05.17 10:40 •
  • lany •
  • #328240 •
  • Хабрахабр •
  • 15
  • 3500

Поиск

Самые читаемые:

Самые обсуждаемые:

2015 ITnan.ru Design by Styleshout.

Права на текст статей, расположенные на сайте, принадлежат их авторам. Источники статей: Хабрахабр и Гиктаймс.

Java 10 проблема миграции, связанная со сбором и генериками

В продолжение моего предыдущего запроса по ссылке: Swing проблема на Java 10, я нахожу еще несколько проблем (выделяя только ошибки), на этот раз я вижу, что проблемы в основном находятся в коллекции API после перехода на java 10.

Читать еще:  Сломался жесткий диск как восстановить данные?

Ниже приведена ошибка. Хотелось бы знать, есть ли какие-либо серьезные изменения в Java 10 при миграции с Java 8 (С точки зрения коллекции/дженериков).

WMTreeNode расширяет javax.swing.tree.DefaultMutableTreeNode .

1 Ответ

Проблема

Если вы внимательно сравните код в DefaultMutableTreeNode между Java 8 и 10, вы увидите, что возвращаемые типы были обобщены:

Ваш код такого рода:

Ваш код компилируется на Java 8, так как добавление дженериков к необработанному типу возможно по соображениям совместимости. Хотя могут быть проблемы (фактически такие же, как ниже), необработанные типы считаются небезопасными в любом случае, поэтому их следует ожидать.

Он больше не компилируется на Java 10, потому что исходный API хочет вернуть Enumeration

Чтобы понять эту последнюю скобку более подробно, предположим, что это были List

Решение

Если бы DefaultMutableTreeNode был моим кодом, я бы изменил breadthFirstEnumeration , чтобы вернуть Enumeration (я понятия не имею, почему это не так). Это заставит ваш код компилироваться.

Поскольку это не вариант, похоже, вам придется это сделать:

    освободите более точную информацию о типе и измените типы возвращаемых переопределений на Enumeration

если вам нужен более точный тип возвращаемого значения, создайте новый метод:

Похожие вопросы:

Я добавляю новую модель, запускаю schemamigration. Затем добавьте данные в эту таблицу с помощью миграции данных. Я запускаю это на Postgres db. Я успешно запустил его на SQLite db локально, поэтому.

Iv’e кодирует a ObjectLoader, который принимает a .obj-файл, и он дает мне то, что я хочу. Моя проблема заключается в том, что при обработке больших файлов(даже не таких больших, около 80 КБ) я в.

Я использую оба ruby на rails и Java. Мне очень нравится использовать миграции, когда я работаю над проектом rails. поэтому мне интересно, есть ли миграция, как инструмент для Java? Если такого.

В Java, как правило, некоторые реализации коллекции позволяют null элементов, а некоторые нет. Это как-то связано со сбором мусора?

Я использую flyway 3.0 для миграции БД. До сих пор я использовал его только с SQL скриптами. DB: mySql. Эти сценарии хранились в src/main/resources под db.migration. Теперь я хочу добавить файл.

Я добавил пролете 5.0.2 зависимостей для моего build.gradle и установить baseline-on-migrate: true на мой application.yml . У меня есть каталог /resources/db/migration . Базовая запись создается в.

Используя массивы, что главная разница между сбором и каждого? Предпочтения? some = [] some.collect do <|x| puts x>some.each do |x| puts x end

Как Storm справляется со сбором мусора? И в чем причина его быстрого выполнения. Это потому, что Разрушитель-шаблон или есть еще одна вещь, которую я упускаю.

могу ли я использовать Java 10 и JHipster (с какой версии выпуска)? Мы построили наше приложение JHipster с Java 8 в один момент времени, с JHipster 4.13.3. Можем ли мы теперь просто использовать.

голоса
Рейтинг статьи
Ссылка на основную публикацию
Статьи c упоминанием слов: