Дублированная и наложенная иерархия классов без проблем строит - PullRequest
0 голосов
/ 29 января 2020

Итак, у меня есть Scala + многомодульная иерархия проектов Maven:

- pom.xml
- nested1
| - pom.xml
| - src
  | - main
    | - scala
      | - ...
      | - MyClass.scala
      | - ...
- nested2
| - pom.xml
| - src
  | - main
    | - scala
      | - ...
      | - MyClass.scala
      | - ...
- app
| - pom.xml
| - Main.scala

По сути, проекты nested1 и nested2 имеют точно одинаково иерархия классов: они объявляют одни и те же классы, одинаковые черты, все они имеют одинаковое содержание, и поэтому c.

app/pom.xml имеет следующие зависимости:

<dependency>
    <groupId>${project-package}</groupId>
    <artifactId>nested1</artifactId>
    <version>1.0</version>
</dependency>
<dependency>
    <groupId>${project-package}</groupId>
    <artifactId>nested2</artifactId>
    <version>1.0</version>
</dependency>

The * Класс 1014 * на самом деле импортирует MyClass в строке 1, но (я бы предположил) он не может сказать, какую версию выбрать: и nested1/src/main/scala/${project-package}/MyClass.scala, и nested2/src/main/scala/${project-package}/MyClass.scala имеют одинаковые ${project-package}.

Я действительно попробовал этот сценарий, и maven, кажется, выбирает наугад один из двух классов, даже не выдав ни одного предупреждения или ошибки.

Что происходит за кулисами? Почему я не получаю сообщение об ошибке типа «неоднозначный оператор импорта: MyClass в строке 1 в Main»?

1 Ответ

1 голос
/ 30 января 2020

Вы не видите ошибок, как вы описываете, потому что эта ситуация явно не поддерживается JVM. Он даже не связан с Scala напрямую: он находится на уровне JVM, здесь нет такой вещи, как «библиотеки», есть только плоский путь к классам (до JPMS в любом случае), где имена классов должны быть уникальными.

В общем, такая ситуация должна никогда случиться - вы просто не можете иметь разные классы, имеющие одно и то же полное имя (в основном пакет + имя класса) в одном загрузчике классов (или чаще в пределах одной ветви дерева загрузчиков классов). Если вы это сделаете, то, что происходит, не определено. Это похоже на концепцию «неопределенного поведения» в C / C ++: среда выполнения просто предполагает, что для данного имени может быть только один класс, и может свободно вести себя на основе этого предположения; В зависимости от конфигурации загрузчиков классов, вы можете получить случайный результат, некоторый фиксированный результат, ошибку во время загрузки классов или любую их комбинацию. Вещи становятся еще более забавными , когда у вас есть зависимости, которые, в свою очередь, зависят от разных версий одного и того же класса, что приводит к целому ряду потенциальных исключений во время выполнения.

Это часть очень известная проблема мира JVM, так называемый classpath / JAR hell . По сути, если ваш проект достаточно сложен, чтобы иметь транзитивные или прямые зависимости от разных версий одной и той же библиотеки или, в частности, от одного и того же набора имен классов, вы будете страдать . Количество страданий зависит от сложности вашей ситуации: в некоторых случаях достаточно иметь только одну версию библиотеки в classpath (что может потребовать некоторых настроек в конфигурации сборки); в других случаях вам придется выполнить shading (что является точным способом решения проблемы, с которой вы столкнулись) для определенного подмножества ваших зависимостей. В еще более сложных случаях затенение не будет работать, и вам придется пересмотреть свою архитектуру. В зависимости от вашей среды вам может понадобиться использовать такие инструменты, как OSGi или даже новую Java Platform Module System для решения проблем пути к классам.

Обратите внимание, что с JPMS , эта конкретная ситуация становится немного лучше: у Java модулей по проекту не может быть одного и того же пакета, определенного в нескольких модулях, загруженных одной и той же JVM, поэтому, если вы компилируете свои проекты как надлежащие модули и пытаетесь использовать их в третьем проекте Во время запуска вы получите исключение из-за конфликтующих модулей. При этом у меня нет большого опыта работы с JPMS, поэтому я не могу сказать, как именно он будет работать, особенно с Scala в миксе.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...