Неполная инъекция в сплетение контейнера при перемещении предметов в отдельном потоке

У меня есть следующий упрощенный пример с контейнером сплетения:

package de.vogel612.depanalyzer;

import de.vogel612.depanalyzer.dependency.MavenResolutionTaskReal;
import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
import org.apache.maven.artifact.repository.layout.DefaultRepositoryLayout;
import org.apache.maven.artifact.repository.layout.FlatRepositoryLayout;
import org.apache.maven.repository.internal.MavenRepositorySystemUtils;
import org.codehaus.plexus.DefaultPlexusContainer;
import org.codehaus.plexus.PlexusContainer;
import org.eclipse.aether.RepositorySystem;
import org.eclipse.aether.connector.basic.BasicRepositoryConnectorFactory;
import org.eclipse.aether.impl.RemoteRepositoryManager;
import org.eclipse.aether.spi.connector.RepositoryConnectorFactory;
import org.eclipse.aether.spi.connector.transport.TransporterFactory;
import org.eclipse.aether.spi.locator.ServiceLocator;
import org.eclipse.aether.transport.file.FileTransporterFactory;
import org.eclipse.aether.transport.http.HttpTransporterFactory;

public class MCVE {

    private static final ServiceLocator serviceLocator = MavenRepositorySystemUtils.newServiceLocator()
            .addService(RepositoryConnectorFactory.class, BasicRepositoryConnectorFactory.class)
            .addService(TransporterFactory.class, FileTransporterFactory.class)
            .addService(TransporterFactory.class, HttpTransporterFactory.class);


    private static final PriorityBlockingQueue<ResolutionTask> taskQueue = new PriorityBlockingQueue<>();
    private static final ExecutorService consumer = Executors.newSingleThreadExector();
    // actually initialized in main, since number of threads is configurable
    private static ExecutorService workers = Executors.newFixedThreadPool(threads, runnable -> {
            Thread result = new Thread(runnable, "WorkerQueue Thread");
            result.setDaemon(true);
            return result;
        });

    public static void main(String[] args) throws Exception {

        PlexusContainer container = new DefaultPlexusContainer();
        // bind eclipse aether RepositorySystem
        container.addComponent(serviceLocator.getService(RepositorySystem.class), RepositorySystem.class, "default");
        container.addComponent(serviceLocator.getService(RemoteRepositoryManager.class), RemoteRepositoryManager.class, "default");

        container.addComponent(new DefaultRepositoryLayout(), ArtifactRepositoryLayout.class, "default");
        container.addComponent(new FlatRepositoryLayout(), ArtifactRepositoryLayout.class, "flat");

        taskQueue.put(container.lookup(MavenResolutionTask.class));
        // ... 
    }
}

Обратите внимание на два последних container.addComponent линий. Теперь, когда я использую контейнер в следующей настройке, я заметил очень любопытное поведение:

public class ResolutionTask extends CompletableFuture<List<SomeType>> implements Runnable { 
    // actually contains an override for run, which does error handling
}

public class MavenResolutionTask extends ResolutionTask {
    @Requires
    Maven mavenInstance;

    @Override
    public void run() {
        // use the maven instance to compute some stuff:
        complete(Collections.singletonList());
    }
}

Этот код работает просто отлично и работает как задумано:

List<DependencyResult> results = new ArrayList<>();
while (!taskQueue.isEmpty()) {
    ResolutionTask currentTask = taskQueue.poll();
    workers.execute(currentTask);
    results.addAll(currentTask.join());
}
results.forEach(System.out::println);

И как только этот упрощенный обработчик рабочей очереди перемещается из основного потока следующим образом, я получаю исключение:

consumer.execute(() -> {
    List<DependencyResult> results = new ArrayList<>();
    while (!taskQueue.isEmpty()) {
        ResolutionTask currentTask = taskQueue.poll();
        workers.execute(currentTask);
        results.addAll(currentTask.join());
    }
    results.forEach(System.out::println);
});

Exception in thread "pool-1-thread-1" java.util.concurrent.CompletionException: java.lang.RuntimeException: Exception occurred during maven invocation
    at java.util.concurrent.CompletableFuture.reportJoin(CompletableFuture.java:375)
    at java.util.concurrent.CompletableFuture.join(CompletableFuture.java:1934)
    at de.vogel612.depanalyzer.Main.lambda$main$1(Main.java:109)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.RuntimeException: Exception occurred during maven invocation
    at de.vogel612.depanalyzer.dependency.MavenResolutionTask.runImpl(MavenResolutionTask.java:35)
    at de.vogel612.depanalyzer.dependency.ResolutionTask.run(ResolutionTask.java:27)
    ... 3 more
    Suppressed: org.apache.maven.InternalErrorException: Internal error: java.lang.NullPointerException
        at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:164)
        at de.vogel612.depanalyzer.dependency.MavenResolutionTask.runImpl(MavenResolutionTask.java:32)
        ... 4 more
    Caused by: java.lang.NullPointerException
        at org.apache.maven.RepositoryUtils.getLayout(RepositoryUtils.java:217)
        at org.apache.maven.RepositoryUtils.toRepo(RepositoryUtils.java:201)
        at org.apache.maven.RepositoryUtils.toRepos(RepositoryUtils.java:191)
        at org.apache.maven.project.DefaultProjectBuilder$InternalConfig.<init>(DefaultProjectBuilder.java:684)
        at org.apache.maven.project.DefaultProjectBuilder.build(DefaultProjectBuilder.java:340)
        at org.apache.maven.DefaultMaven.collectProjects(DefaultMaven.java:637)
        at org.apache.maven.DefaultMaven.getProjectsForMavenReactor(DefaultMaven.java:586)
        at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:229)
        at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:152)
        ... 5 more

"Основная причина" этого исключения указывает на место, которое на самом деле не полезно. Когда maven пытается инициализировать удаленный репозиторий, он обращается к Map<String, ArtifactRepositoryLayout>, который должен содержать записи {"default", new DefaultRepositoryLayout()},{"flat", new FlatRepositoryLayout()}, но не

Эта карта может быть найдена в LegacyRepositorySystem maven-compat, но она не правильно инициализируется при доступе к taskQueue в consumer,
Код выдает правильный вывод при consumer вне уравнения...

Почему это происходит?

0 ответов

Другие вопросы по тегам