Несколько версий одной и той же зависимости в 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?
@ Редактировать Любой обходной путь, возможно?
5 ответов
Нет. Maven разрешит только одну зависимость в вашем модуле и пропустит другие версии, чтобы избежать конфликта. Даже если во всей иерархии зависимостей используются несколько версий одной и той же зависимости, Maven выберет одну версию, используя стратегию "ближайшая в дереве зависимостей".
Можно указать разные версии зависимостей, используя разные профили. Для каждой версии 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>
Попробуй обмануть мавена
<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>
Вот соответствующая часть документации Maven, в которой объясняется, как Maven выбирает версию зависимости, когда существует более одной возможности:
Посредничество зависимостей - это определяет, какая версия артефакта будет выбрана, когда несколько версий обнаруживаются как зависимости. Maven выбирает "ближайшее определение". То есть он использует версию наиболее близкой к вашему проекту зависимости в дереве зависимостей. Вы всегда можете гарантировать версию, явно указав ее в POM вашего проекта. Обратите внимание: если две версии зависимостей находятся на одной и той же глубине в дереве зависимостей, первое объявление выигрывает. "ближайшее определение" означает, что используемая версия будет самой близкой к вашему проекту в дереве зависимостей. Рассмотрим это дерево зависимостей:
A
├── B
│ └── C
│ └── D 2.0
└── E
└── D 1.0
В тексте зависимости для A, B и C определены как A -> B -> C -> D 2.0 и A -> E -> D 1.0, тогда D 1.0 будет использоваться при построении A, потому что путь от A до От D до E короче. Вы можете явно добавить зависимость от D 2.0 в A, чтобы принудительно использовать D 2.0, как показано здесь:
A
├── B
│ └── C
│ └── D 2.0
├── E
│ └── D 1.0
│
└── D 2.0
Нет, вы не можете полагаться на 2 версии одного и того же артефакта, как правило.
Но вы можете включить их, чтобы они оказались в конечном приложении.
Но это требование иногда действительно - например, когда обслуживание этой библиотеки плохое, и они перемещают много пакетов и объявляют эту младшую версию одного и того же артефакта. Затем разные библиотеки используют это как стороннюю зависимость и требуют разных одинаковых классов в разных FQCN.
В таких случаях вы можете, например, использовать maven-shade-plugin
,
- Создайте проект maven с одной зависимостью, одной из нужных вам версий.
- Добавить
shade
Плагин, и пусть он создает затененную банку. Это будет в основном переупаковывать классы под другим артефактом G:A:V. - Сделайте это для всех версий, которые вам нужны.
- Вы можете использовать классификатор, чтобы различать затененные версии.
- В вашем проекте зависят от этих артефактов.
- Наконец, исключите исходные зависимости, дайте им область "предоставлено".
Вы можете использовать разные варианты одного и того же, что в итоге поместит эти классы в ваш путь к классам. Например, используйте dependency:copy-dependency
плагин / цель, и установите этот jar в локальный репозиторий во время сборки. Или распакуйте классы прямо в свой ${project.build.outputDirectory}
(целевые / классы).
Я все еще довольно новичок, но кое-что, с чем я столкнулся с axis2, заключается в том, что отдельным модулям иногда требуется более ранняя версия из-за изменений, которые они внесли в классы, поэтому зависимость верхнего уровня ловит только половину из них. Остальное мне приходилось индивидуально исправлять poms для явных зависимостей в другой версии.
Может быть, такой подход подойдет и вам? Наличие плагина имеет модульные компоненты для их конкретных зависимостей.
Вот сценарий, в котором может возникнуть проблема, когда maven рассматривает только один экземпляр зависимости.
Проект зависит от двух других проектов, и, в свою очередь, оба других проекта зависят от третьего проекта, но различаются подмножествами (т.е. используют исключение).
Желаемый эффект состоит в том, что конечный проект включает объединенное подмножество, но на самом деле он будет включать только одно подмножество.
В большом проекте вполне возможно, что есть ромбовидные зависимости. В этом случае нужно быть очень осторожным при использовании исключений.
Вот как я обошел это. К вашему сведению: в моем случае я строил 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>