Пакет конфликтует с автоматическими модулями в Java 9

С приближением Java 9 я подумал, что будет хорошим учебным упражнением перенести некоторые из моих проектов на Java 9. В одном из моих проектов у меня есть зависимости для rxjava и rxjavafx

dependencies {
    compile 'io.reactivex:rxjava:1.2.6'
    compile 'io.reactivex:rxjavafx:1.0.0'
    ...
}

Я хочу создать этот проект как именованный модуль. Для этого мне нужно создать module-info.java файл и указать здесь требования для rxjava и rxjavafx. Однако в этих библиотеках пока нет информации о модулях.

Чтобы обойти это, я прочитал, что мне нужно создать автоматический Модули. Насколько я понимаю, мне нужно переименовать банки rxjava и rxjavafx, чтобы они имели простое имя, а затем перечислить банки в параметре --module-path. Затем я добавляю директиву requires в свой module-info.java с именами банок.

module com.foo.bar {
    requires rxjavafx;
    requires rxjava;
}

Я написал задачу gradle, чтобы отредактировать для меня имена jar-файлов, и, похоже, в большинстве случаев она работает. Он берет все jar-файлы, которые необходимо скомпилировать, и переименовывает их, чтобы не включать информацию о версии или косые черты. Затем файлы объединяются в строку, разделенную ::

tasks.withType(JavaCompile) {
    delete { delete '/tmp/gradle' }
    copy {
        from configurations.compile + configurations.testCompile
        into '/tmp/gradle'
        rename '(.*)-[0-9]+\\..*.jar', '$1.jar'
        rename { String fileName -> fileName.replace("-", "") }
    }
    options.compilerArgs += ['--module-path', fileTree(dir: '/tmp/gradle', include: '*.jar').getFiles().join(':')]
}

Естественно, библиотеки rx используют одни и те же имена пакетов ... однако это заставляет компилятор выдавать такие ошибки, как:

error: module  reads package rx.subscriptions from both rxjava and rxjavafx
error: module  reads package rx.schedulers from both rxjava and rxjavafx
error: module  reads package rx.observables from both rxjava and rxjavafx
error: module rxjava reads package rx.subscriptions from both rxjavafx and rxjava
error: module rxjava reads package rx.schedulers from both rxjavafx and rxjava
error: module rxjava reads package rx.observables from both rxjavafx and rxjava
error: module rxjavafx reads package rx.subscriptions from both rxjava and rxjavafx
error: module rxjavafx reads package rx.schedulers from both rxjava and rxjavafx
error: module rxjavafx reads package rx.observables from both rxjava and rxjavafx

Похоже, что единственный способ обойти эту проблему - переупаковать содержимое rxjava и rxjavafx в одну банку и добавить ее как один модуль. Хотя это не кажется хорошим решением ...

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

  • Правильно ли я использую новую модульную систему?
  • Что мне делать с этой ошибкой? а также
  • Эти зависимости мешают мне обновляться, или мне просто нужно дождаться, пока rx обновит свои библиотеки?

Примечание. Я пробовал запускать это со стандартным _17 _ / _ 18_, и они вызывают те же проблемы. Также вот моя версия java:

java version "9-ea"
Java(TM) SE Runtime Environment (build 9-ea+140)
Java HotSpot(TM) 64-Bit Server VM (build 9-ea+140, mixed mode)

person flakes    schedule 21.02.2017    source источник
comment
Небольшие улучшения (возможно): при извлечении имени модуля из имени JAR система модулей будет выдавать подстроки, похожие на версии ~ ›попробуйте, не переименовывая их. Путь к модулю также принимает каталоги ~ ›если у вас есть каталог, который содержит только зависимости, поместите его напрямую в путь к модулю.   -  person Nicolai Parlog    schedule 21.02.2017
comment
Не связанный с вашим текущим вопросом, я бы предложил перейти на более новую сборку JDK 9. Сборка 148 (я думаю) внесла некоторые существенные изменения в доступность частных типов и членов через отражение. Текущая сборка - 157.   -  person Stuart Marks    schedule 21.02.2017


Ответы (3)


Правильно ли я использую новую модульную систему?

да. То, что вы видите, является предполагаемым поведением, и это связано с тем, что модули JPMS не допускают разделение пакетов.

Если вы не знакомы с термином «разделенные пакеты», он, по сути, означает два члена одного и того же пакета, происходящие из двух разных модулей.

Например:
com.foo.A (из moduleA.jar)
com.foo.B (из moduleB.jar)

Что мне делать с этой ошибкой?

У вас есть два варианта:

  1. (сложнее) "разделить" зависимости пакета. Однако это может быть сложно или невозможно, если вы не знакомы с внутренней работой библиотеки.
  2. (проще) объедините две банки в одну (и, следовательно, один автоматический модуль), как вы упомянули выше. Я согласен с тем, что это не «хорошее» решение, но, в первую очередь, разделение пакетов - тоже не лучшая идея.

Эти зависимости мешают мне обновляться, или я должен просто подождать, пока rx обновит свои библиотеки?

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

person Andy Guibert    schedule 21.02.2017
comment
Хм, немного обидно слышать. Думаю, было бы несложно написать задачу gradle для объединения разделенных пакетов. Хотя надо быть умным. Не хочу разрушать мое время сборки, переупаковывая чужие библиотеки ¯ \ _ (ツ) _ / ¯ - person flakes; 21.02.2017
comment
Да, это больно, но, черт возьми, запрет на разделение пакетов дает преимущества в плане безопасности и производительности. Надеюсь, владельцы библиотек быстро предоставят комбинированные jar-файлы. Или я мог видеть, как maven central предоставляет автоматические комбинированные банки. - person Andy Guibert; 21.02.2017
comment
Забавно читать заметки о миграции java 9, что jdk9 вряд ли сломает ваш код. Но это ограничение нарушает работу множества библиотек. Разделение пакетов - очень распространенная практика для библиотек, которые распространяются через несколько jar-файлов. - person eugcomax; 23.02.2017
comment
@eugcomax Важно отметить, что есть 2 отдельных этапа миграции JDK 9: 1) терпимость к java 9 (т.е. запуск приложений как безымянных модулей), а затем 2) принятие java 9 (т.е. преобразование приложений для использования информации о модулях, чтобы они называются модулями). Я считаю, что на этапе 1 очень маловероятно, что код людей будет нарушен, но этап 2, без сомнения, станет большой головной болью. - person Andy Guibert; 23.02.2017
comment
Это грустно. По сути, это означает, что я не могу использовать аннотации jsr305, потому что они находятся в пакете javax.annotation, который уже существует в java.base. - person ZhekaKozlov; 06.04.2017
comment
Вероятно, вы используете очень старую сборку JDK. Аннотации jsr305 уже некоторое время находятся в собственном модуле, который не включен в агрегатный модуль java.se. Таким образом, этот модуль по умолчанию не добавляется в JDK. - person Andy Guibert; 06.04.2017
comment
Вы можете мне объяснить, как я могу разбить две банки в одну? Например, когда у меня возникает эта ошибка: [ERROR] module validation.api читает пакет javax.annotation как из tomcat.embed.core, так и из java.xml.ws.annotation - person hudi; 22.06.2017
comment
вы можете разархивировать две банки в один и тот же каталог, а затем заархивировать их в один архив (и переименовать расширение файла с .zip на .jar) - person Andy Guibert; 22.06.2017
comment
@AndyGuibert ну ... что, если мне нужны два jar-файла через requires в моем module-info.java, но они оба содержат одно и то же имя пакета? Похоже, именно это и происходит с нами сейчас. Я понимаю, что простое переименование должно работать, но мы получаем эти jar-файлы от третьих лиц, что делает это немного неприятным. Или, может быть, я что-то упускаю? - person Eugene; 16.07.2018

У меня была похожая проблема:

error: module flyway.core reads package javax.transaction.xa from both jboss.transaction.api.1.2.spec and java.sql
error: module slf4j.api reads package javax.transaction.xa from both jboss.transaction.api.1.2.spec and java.sql
error: module hibernate.core reads package javax.transaction.xa from both jboss.transaction.api.1.2.spec and java.sql
.../src/main/java/module-info.java:1: error: module eu.com.x reads package javax.transaction.xa from both java.sql and jboss.transaction.api.1.2.spec

Я мог бы избавиться от проблемы компиляции разделенных пакетов, проверив транзитивные зависимости моего проекта (могут быть полезны "gradle dependencies" или "mvn dependency: tree") и исключив код, похожий на:

configurations.all {
    exclude group: 'org.jboss.spec.javax.transaction', module: 'jboss-transaction-api_1.2_spec'
}

or

<dependencies>
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-core</artifactId>
      <version>5.2.10.Final</version>
      <exclusions>
        <exclusion>
          <groupId>org.jboss.spec.javax.transaction</groupId>
          <artifactId>jboss-transaction-api_1.2_spec</artifactId>
        </exclusion>
      </exclusions> 
    </dependency>
  </dependencies>

Моя проблема не требовала переупаковки банок. Эта проблема не возникала на # JDK8. Вероятно, исключение зависимостей помогает не во всех проектах.

person Radosław Osiński    schedule 13.08.2017
comment
У меня точно такая же проблема, но в этом случае исключение зависимости boss-transaction-api_1.2_spec не сработало. Он содержит дополнительные классы в своем java.transaction.xa пакете, которые не находятся в том же пакете, экспортированном модулем java.sql. Следовательно, вместо этого я получаю java.lang.ClassNotFoundException исключения времени выполнения. Мне, возможно, придется «немодулировать» мой проект, пока проблема не будет решена. - person Paul; 06.10.2017

Я столкнулся с той же проблемой с пакетом чтения java.transaction.xa как из javaee, так и из java.transaction.xa. И я исправил это, добавив эту строку в свой modul-info.java

 opens javax.transaction.xa;

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

person kamel2005    schedule 30.10.2018