Как заставить новый API внедрения зависимостей Maven 4 работать одинаково в плагине Maven между тестированием и производJAVA

Программисты JAVA общаются здесь
Ответить
Anonymous
 Как заставить новый API внедрения зависимостей Maven 4 работать одинаково в плагине Maven между тестированием и производ

Сообщение Anonymous »

Я экспериментировал с новым API внедрения зависимостей Maven 4. Этот API заменяет аннотации Plexus и
JSR 330 в соответствии с этим руководством:

Maven DI — это платформа внедрения зависимостей Maven, представленная в Maven 4.
Он является преемником Plexus IoC (используется в Maven 2) и JSR 330/Eclipse Sisu (используется в Maven 3) в Maven.

Насколько я могу судить, с новыми API есть два способа получения сервисов:
  • Внедрение зависимостей с помощью новой аннотации @org.apache.maven.api.di.Inject.
  • Внедрение сеанса и последующий вызов Session::getService(Class).
Однако я наблюдаю разное поведение при модульном тестировании моего плагина Maven и использовании плагина в отдельном проекте.
Во время модульных тестов все службы успешно внедряются с помощью @Inject. Но затем плагину не удается внедрить
те же службы при использовании в проекте. И наоборот, получение сервисов через Session::getService завершается неудачно во время
модульных тестов, но успешно при использовании в проекте. Таким образом, не только получение сервисов, по-видимому, ведет себя по-разному
между тестами и «производством», но и разные API, которые «делают одно и то же», терпят неудачу в противоположных точках. Я нахожу это довольно
странным. Я ожидал, что либо getService будет намного более надежным, чем DI, либо что getService и @Inject
в конечном счете будут использовать одну и ту же реализацию «под капотом» (то есть они должны вести себя одинаково).
Что я делаю не так? Должен ли я вообще тестировать Mojos таким образом?
Я предполагаю, что это, скорее всего, моя вина, поскольку я тестирую с Maven 4.0.0-rc-4, четвертым релизом
кандидата (вместо бета-версии или еще менее стабильной версии). Кроме того, желание внедрить сервисы должно быть общим
желанием, поэтому я предполагаю, что это хорошо протестированная функция.
Я предполагаю, что проблема в том, как «подключены» модульные тесты.

Минимальный пример
Использовались Maven 4.0.0-rc-4 и Java 24.0.1. Я не считаю, что версия Java имеет значение, если это Java 17+.
Репозиторий GitLab
Чтобы помочь с воспроизведением проблемы, вот репозиторий GitLab с приведенным ниже примером: https://gitlab.com/tkslaw/maven4-di-tests.
Результаты



Mojo
Юнит-тест
Интеграционный тест ("производство")




GetServiceMojo
Не удалось
Успешно


InjectServiceMojo
Успешно
Не удалось



Исходный код
POM



4.1.0

com.gitlab.tkslaw
ditests-maven-plugin
0.1.0-SNAPSHOT
maven-plugin


UTF-8
17

[4.0.0-rc-4]

4.0.0-rc-4
5.13.4
7.0.0






org.apache.maven
maven-api-core
${mavenVersion}
provided


org.apache.maven
maven-api-di
${mavenVersion}
provided





org.junit.jupiter
junit-jupiter
${junitVersion}
test





org.apache.maven
maven-testing
${mavenVersion}
test




com.google.inject
guice
${guiceVersion}
test








org.apache.maven.plugins
maven-clean-plugin
3.5.0


org.apache.maven.plugins
maven-compiler-plugin
3.14.0


org.apache.maven.plugins
maven-resources-plugin
3.3.1


org.apache.maven.plugins
maven-surefire-plugin
3.5.3


org.apache.maven.plugins
maven-jar-plugin
3.4.2


org.apache.maven.plugins
maven-plugin-plugin
4.0.0-beta-1


org.apache.maven.plugins
maven-invoker-plugin
3.9.1


org.apache.maven.plugins
maven-enforcer-plugin
3.6.1






org.apache.maven.plugins
maven-enforcer-plugin



${requiredMavenVersion}





enforce
validate

enforce






org.apache.maven.plugins
maven-plugin-plugin


java-annotations





org.apache.maven.plugins
maven-surefire-plugin

-XX:+EnableDynamicAgentLoading
true




org.apache.maven.plugins
maven-invoker-plugin

${project.build.directory}/it

${project.build.directory}/local-repo

validate




integration-test

install
run








Основной код
DITestsMojoBase.java
package com.gitlab.tkslaw.ditests;

import org.apache.maven.api.Project;
import org.apache.maven.api.Session;
import org.apache.maven.api.di.Inject;
import org.apache.maven.api.plugin.Log;
import org.apache.maven.api.plugin.Mojo;

public class DITestsMojoBase implements Mojo {

@Inject protected Log log;
@Inject protected Session session;
@Inject protected Project project;

@Override
public void execute() {
log.info(() -> "log = " + log);
log.info(() -> "session = " + session);
log.info(() -> "project = " + project);
}

protected void logService(String name, Object service) {
log.info(() -> " | %s = %s".formatted(name, service));
}
}

GetServiceMojo.java
package com.gitlab.tkslaw.ditests;

import org.apache.maven.api.plugin.annotations.Mojo;
import org.apache.maven.api.services.ArtifactManager;
import org.apache.maven.api.services.DependencyResolver;
import org.apache.maven.api.services.OsService;
import org.apache.maven.api.services.ToolchainManager;

@Mojo(name = "get-service")
public class GetServiceMojo extends DITestsMojoBase {

protected ArtifactManager artifactManager;
protected DependencyResolver dependencyResolver;
protected ToolchainManager toolchainManager;
protected OsService osService;

@Override
public void execute() {
super.execute();

artifactManager = session.getService(ArtifactManager.class);
dependencyResolver = session.getService(DependencyResolver.class);
toolchainManager = session.getService(ToolchainManager.class);
osService = session.getService(OsService.class);

log.info("Logging services obtained via Session::getService");
logService("artifactManager", artifactManager);
logService("dependencyResolver", dependencyResolver);
logService("toolchainManager", toolchainManager);
logService("osService", osService);
}
}

InjectServiceMojo.java
package com.gitlab.tkslaw.ditests;

import org.apache.maven.api.di.Inject;
import org.apache.maven.api.plugin.annotations.Mojo;
import org.apache.maven.api.services.ArtifactManager;
import org.apache.maven.api.services.DependencyResolver;
import org.apache.maven.api.services.OsService;
import org.apache.maven.api.services.ToolchainManager;

@Mojo(name = "inject-service")
public class InjectServiceMojo extends DITestsMojoBase {

@Inject protected ArtifactManager artifactManager;
@Inject protected DependencyResolver dependencyResolver;
@Inject protected ToolchainManager toolchainManager;
@Inject protected OsService osService;

@Override
public void execute() {
super.execute();

log.info("Logging services injected via @Inject");
logService("artifactManager", artifactManager);
logService("dependencyResolver", dependencyResolver);
logService("toolchainManager", toolchainManager);
logService("osService", osService);
}
}

Тестовый код
GetServiceMojoTests.java
package com.gitlab.tkslaw.ditests;

import org.apache.maven.api.plugin.testing.InjectMojo;
import org.apache.maven.api.plugin.testing.MojoTest;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertAll;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertNotNull;

@MojoTest
@DisplayName("Test GetServiceMojo")
class GetServiceMojoTests {

@Test
@InjectMojo(goal = "get-service")
@DisplayName("initialized its services via Session::getService")
void testServicesNotNull(GetServiceMojo mojo) {
// Preconditions
assertAll(
"Log, Session, and/or Project were not injected. This should not happen!",
() -> assertNotNull(mojo.log, "log"),
() -> assertNotNull(mojo.session, "session"),
() -> assertNotNull(mojo.project, "project"));

// Actual test
assertDoesNotThrow(mojo::execute, "GetServiceMojo::execute");
assertAll(
"Services not obtained from Session::getService",
() -> assertNotNull(mojo.artifactManager, "artifactManager"),
() -> assertNotNull(mojo.dependencyResolver, "dependencyResolver"),
() -> assertNotNull(mojo.toolchainManager, "toolchainManager"),
() -> assertNotNull(mojo.osService, "osService"));
}
}

InjectServiceMojoTests.java
package com.gitlab.tkslaw.ditests;

import org.apache.maven.api.plugin.testing.InjectMojo;
import org.apache.maven.api.plugin.testing.MojoTest;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertAll;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertNotNull;

@MojoTest
@DisplayName("Test InjectServiceMojo")
class InjectServiceMojoTests {

@Test
@InjectMojo(goal = "inject-service")
@DisplayName("had its services injected by the DI container")
void testServicesNotNull(InjectServiceMojo mojo) {
// Preconditions
assertAll(
"Log, Session, and/or Project were not injected. This should not happen!",
() -> assertNotNull(mojo.log, "log"),
() -> assertNotNull(mojo.session, "session"),
() -> assertNotNull(mojo.project, "project"));

// Actual test
assertDoesNotThrow(mojo::execute, "InjectServiceMojo::execute");
assertAll(
"Services not injected by DI container",
() -> assertNotNull(mojo.artifactManager, "artifactManager"),
() -> assertNotNull(mojo.dependencyResolver, "dependencyResolver"),
() -> assertNotNull(mojo.toolchainManager, "toolchainManager"),
() -> assertNotNull(mojo.osService, "osService"));
}
}

Код теста интеграции
src/it/get-service/pom.xml

4.1.0

com.gitlab.tkslaw
get-service
0.1.0-SNAPSHOT




org.apache.maven.plugins
maven-enforcer-plugin
3.6.1



@requiredMavenVersion@





enforce
validate

enforce






com.gitlab.tkslaw
ditests-maven-plugin
@project.version@


get-service
validate

get-service









src/it/inject-service/pom.xml

4.1.0

com.gitlab.tkslaw
inject-service
0.1.0-SNAPSHOT




org.apache.maven.plugins
maven-enforcer-plugin
3.6.1



@requiredMavenVersion@





enforce
validate

enforce






com.gitlab.tkslaw
ditests-maven-plugin
@project.version@


inject-service
validate

inject-service









Вывод
Вот результат проверки mvn clean.
Консоль
Вывод модульных тестов:
[INFO] -------------------------------------------------------
[INFO] T E S T S
[INFO] -------------------------------------------------------
[INFO] Running com.gitlab.tkslaw.ditests.GetServiceMojoTests
[WARNING] [stderr] OpenJDK 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended
[WARNING] [stderr] [main] INFO anonymous - log = org.apache.maven.internal.impl.DefaultLog@6296474f
[WARNING] [stderr] [main] INFO anonymous - session = Mock for InternalSession, hashCode: 1390430007
[WARNING] [stderr] [main] INFO anonymous - project = org.apache.maven.api.plugin.testing.stubs.ProjectStub@767f6ee7
[WARNING] [stderr] [main] INFO anonymous - Logging services obtained via Session::getService
[WARNING] [stderr] [main] INFO anonymous - | artifactManager = Mock for ArtifactManager, hashCode: 954928973
[WARNING] [stderr] [main] INFO anonymous - | dependencyResolver = null
[WARNING] [stderr] [main] INFO anonymous - | toolchainManager = null
[WARNING] [stderr] [main] INFO anonymous - | osService = null
[ERROR] Tests run: 1, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 2.174 s expected: not

Suppressed: org.opentest4j.AssertionFailedError: toolchainManager ==> expected: not

Suppressed: org.opentest4j.AssertionFailedError: osService ==> expected: not


[INFO] Running com.gitlab.tkslaw.ditests.InjectServiceMojoTests
[WARNING] [stderr] [main] INFO anonymous - log = org.apache.maven.internal.impl.DefaultLog@3762c4fc
[WARNING] [stderr] [main] INFO anonymous - session = Mock for InternalSession, hashCode: 236055802
[WARNING] [stderr] [main] INFO anonymous - project = org.apache.maven.api.plugin.testing.stubs.ProjectStub@77ab22be
[WARNING] [stderr] [main] INFO anonymous - Logging services injected via @Inject
[WARNING] [stderr] [main] INFO anonymous - | artifactManager = Mock for ArtifactManager, hashCode: 997219303
[WARNING] [stderr] [main] INFO anonymous - | dependencyResolver = org.apache.maven.impl.DefaultDependencyResolver@59fbb34
[WARNING] [stderr] [main] INFO anonymous - | toolchainManager = org.apache.maven.impl.DefaultToolchainManager@1b6924cb
[WARNING] [stderr] [main] INFO anonymous - | osService = org.apache.maven.impl.model.DefaultOsService@3a8d467e
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.084 s -- in com.gitlab.tkslaw.ditests.InjectServiceMojoTests
[INFO]
[INFO] Results:
[INFO]
[ERROR] Failures:
[ERROR] GetServiceMojoTests.testServicesNotNull:29 Services not obtained from Session::getService (3 failures)
org.opentest4j.AssertionFailedError: dependencyResolver ==> expected: not
org.opentest4j.AssertionFailedError: toolchainManager ==> expected: not
org.opentest4j.AssertionFailedError: osService ==> expected: not
[INFO]
[ERROR] Tests run: 2, Failures: 1, Errors: 0, Skipped: 0
[INFO]
[ERROR] There are test failures.

it/get-service/build.log
Только вывод ditests:get-service:
[INFO] --- ditests:0.1.0-SNAPSHOT:get-service (get-service) @ get-service ---
[INFO] log = org.apache.maven.internal.impl.DefaultLog@22a6d75c
[INFO] session = org.apache.maven.internal.impl.DefaultSession@2e43c38d
[INFO] project = org.apache.maven.internal.impl.DefaultProject@382d71c7
[INFO] Logging services obtained via Session::getService
[INFO] | artifactManager = org.apache.maven.internal.impl.DefaultArtifactManager@50598a1a
[INFO] | dependencyResolver = org.apache.maven.impl.DefaultDependencyResolver@14de1901
[INFO] | toolchainManager = org.apache.maven.impl.DefaultToolchainManager@437ed416
[INFO] | osService = org.apache.maven.impl.model.DefaultOsService@11f23038
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------

it/inject-service/build.log
Используйте вывод ditests:inject-service:
[INFO] --- ditests:0.1.0-SNAPSHOT:inject-service (inject-service) @ inject-service ---
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.110 s
[INFO] Finished at: 2025-08-14T11:47:23-06:00
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal com.gitlab.tkslaw:ditests-maven-plugin:0.1.0-SNAPSHOT:inject-service (inject-service) on project inject-service: Execution inject-service of goal com.gitlab.tkslaw:ditests-maven-plugin:0.1.0-SNAPSHOT:inject-service failed: Unable to lookup Mojo: Error while initializing binding BindingToConstructor[@Named("com.gitlab.tkslaw:ditests-maven-plugin:0.1.0-SNAPSHOT:inject-service") InjectServiceMojoFactory][]: No binding to construct an instance for key ArtifactManager. Existing bindings:
[ERROR] - @Named("com.gitlab.tkslaw:ditests-maven-plugin:0.1.0-SNAPSHOT:get-service") DITestsMojoBase
[ERROR] - @Named("com.gitlab.tkslaw:ditests-maven-plugin:0.1.0-SNAPSHOT:get-service") GetServiceMojo
[ERROR] - @Named("com.gitlab.tkslaw:ditests-maven-plugin:0.1.0-SNAPSHOT:get-service") GetServiceMojoFactory
[ERROR] - @Named("com.gitlab.tkslaw:ditests-maven-plugin:0.1.0-SNAPSHOT:get-service") Mojo
[ERROR] - @Named("com.gitlab.tkslaw:ditests-maven-plugin:0.1.0-SNAPSHOT:get-service") Object
[ERROR] - @Named("com.gitlab.tkslaw:ditests-maven-plugin:0.1.0-SNAPSHOT:inject-service") DITestsMojoBase
[ERROR] - @Named("com.gitlab.tkslaw:ditests-maven-plugin:0.1.0-SNAPSHOT:inject-service") InjectServiceMojo
[ERROR] - @Named("com.gitlab.tkslaw:ditests-maven-plugin:0.1.0-SNAPSHOT:inject-service") InjectServiceMojoFactory
[ERROR] - @Named("com.gitlab.tkslaw:ditests-maven-plugin:0.1.0-SNAPSHOT:inject-service") Mojo
[ERROR] - @Named("com.gitlab.tkslaw:ditests-maven-plugin:0.1.0-SNAPSHOT:inject-service") Object
[ERROR] - DITestsMojoBase
[ERROR] - GetServiceMojo
[ERROR] - GetServiceMojoFactory
[ERROR] - InjectServiceMojo
[ERROR] - InjectServiceMojoFactory
[ERROR] - Log
[ERROR] - Mojo
[ERROR] - MojoExecution
[ERROR] - Object
[ERROR] - Project
[ERROR] - ProtoSession
[ERROR] - Session


Подробнее здесь: https://stackoverflow.com/questions/797 ... in-a-maven
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «JAVA»