Несколько версий одной и той же зависимости в Maven

Можно ли объявить несколько версий одной и той же зависимости в репозитории Maven?

Мне нужны эти зависимости сразу:

    <dependency>
        <groupId>org.bukkit</groupId>
        <artifactId>craftbukkit</artifactId>
        <version>1.7.9-R0.2</version>
        <scope>compile</scope>
    </dependency>
    <dependency>
        <groupId>org.bukkit</groupId>
        <artifactId>craftbukkit</artifactId>
        <version>1.7.2-R0.3</version>
        <scope>compile</scope>
    </dependency>
    <dependency>
        <groupId>org.bukkit</groupId>
        <artifactId>craftbukkit</artifactId>
        <version>1.6.4-R2.0</version>
        <scope>compile</scope>
    </dependency>

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

org.bukkit.craftbukkit.v1_6_R3

org.bukkit.craftbukkit.v1_7_R1

org.bukkit.craftbukkit.v1_7_R3

Если я объявляю зависимости, как показано в первом фрагменте, вступает в силу только последний. Есть ли способ достичь этого в Maven?

@Edit Любое обходное решение, возможно?

Ответы

Ответ 1

Нет. Maven разрешит только одну зависимость в вашем модуле и опустит другие версии, чтобы избежать конфликта. Даже если несколько версий одной и той же зависимости используются во всей иерархии зависимостей, Maven выберет одну версию, используя стратегию "ближайшего в дереве зависимостей".

Можно указать разные версии зависимостей, используя различные profiles. Для каждой версии Bukkit можно определить и активировать профиль. Тем не менее, если вы активируете более одного профиля, будет использоваться только одна версия.

<profiles>
    <profile>
        <id>Bukkit_1_7_9_R02</id>
        <activation>
            ...
        </activation>
        <dependencies>
            <dependency>
                <groupId>org.bukkit</groupId>
                <artifactId>craftbukkit</artifactId>
                <version>1.7.9-R0.2</version>
                <scope>compile</scope>
            </dependency>
        </dependencies>
    </profile>
    <profile>
        <id>Bukkit_1_7_2_R03</id>
        <activation>
            ...
        </activation>
        <dependencies>
            <dependency>
                <groupId>org.bukkit</groupId>
                <artifactId>craftbukkit</artifactId>
                <version>1.7.2-R0.3</version>
                <scope>compile</scope>
            </dependency>
        </dependencies>
    </profile>
    ...
</profiles>

Ответ 2

Нет, вы не можете полагаться на 2 версии одного и того же артефакта, как правило.
Но вы можете включить их, чтобы они оказались в конечном приложении.

Это требование иногда справедливо, например, когда обслуживание этой библиотеки плохое, и они переименовывают некоторые пакеты и выпускают их как вспомогательную версию того же артефакта. Тогда другие проекты имеют его как стороннюю зависимость и нуждаются в одних и тех же классах под разными FQCN.

В таких случаях вы можете, например, использовать maven-shade-plugin.

  • Создайте проект maven с одной зависимостью, одной из нужных вам версий.
  • Добавьте shade плагин и пусть это создать тенистую банку. Это будет в основном переупаковывать классы под другим артефактом G: A: V.
  • Сделайте это для всех версий, которые вам нужны.
  • Вы можете использовать классификатор, чтобы различать затененные версии.
  • В вашем проекте зависят от этих артефактов.
  • Наконец, исключите исходные зависимости, дайте им область "предоставлено".

Вы можете использовать разные варианты одного и того же, что в итоге поместит эти классы в ваш путь к классам. Например, используйте плагин/цель dependency:copy-dependency и установите этот jar файл в локальный репозиторий во время сборки. Или распакуйте классы прямо в ваш ${project.build.outputDirectory} (target/classes).

Ответ 3

Я все еще довольно новый, но кое-что, с чем я столкнулся с осью 2, заключается в том, что для отдельных модулей иногда требуется более ранняя версия из-за изменений, внесенных ими в классы, поэтому зависимость верхнего уровня улавливает почти половину их. В остальном мне пришлось индивидуально корректировать poms для явных зависимостей для другой версии.

Возможно, этот подход будет работать и на вас? Наличие плагина имеет модульные компоненты для их конкретных зависимостей.

Ответ 4

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

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

Желаемый эффект заключается в том, что окончательный проект включает объединенное подмножество, но на самом деле он будет включать только одно подмножество.

В большом проекте вполне возможно, что существуют зависимости в форме алмаза. В этом случае вы должны быть очень осторожны при использовании исключений.

Ответ 5

Попробуй обмануть мавена

<dependency>
    <groupId>org.bukkit</groupId>
    <artifactId>craftbukkit</artifactId>
    <version>1.7.9-R0.2</version>
    <scope>compile</scope>
</dependency>
<dependency>
    <groupId>org.bukkit.</groupId>
    <artifactId>craftbukkit</artifactId>
    <version>1.7.2-R0.3</version>
    <scope>compile</scope>
</dependency>
<dependency>
    <groupId>org.bukkit..</groupId>
    <artifactId>craftbukkit</artifactId>
    <version>1.6.4-R2.0</version>
    <scope>compile</scope>
</dependency>

Ответ 6

Вот как я обошел это. К вашему сведению: в моем случае я строил RPM.

Я использовал maven-dependency-plugin чтобы скопировать старую зависимость, которая игнорируется, в папку в каталоге сборки, а затем скопировал этот файл в промежуточную область, чтобы включить его в RPM.

Вот код для копирования старой зависимости:

  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <version>3.1.1</version>
    <executions>
      <execution>
        <id>copy-dependencies</id>
        <phase>prepare-package</phase>
        <goals>
          <goal>copy</goal>
        </goals>
        <configuration>
          <artifactItems>
            <artifactItem>
              <groupId>some.package.group.id</groupId>
              <artifactId>someartifact-id</artifactId>
              <version>1.2.3</version>
              <overWrite>false</overWrite>
              <outputDirectory>${project.build.directory}/older-dependencies</outputDirectory>
            </artifactItem>
          </artifactItems>
        </configuration>
      </execution>
    </executions>
  </plugin>

А потом позже, во время сборки моего RPM, я включил этот скриптлет в раздел configuration моего rpm-maven-plugin. Это скопирует файл в промежуточную область для RPM:

<installScriptlet>
  <script>cp ${project.build.directory}/older-dependencies/* ${project.build.directory}/rpm/${artifactId}/buildroot${installBase}/</script>
</installScriptlet>