[MNG-8249] Provide an annotation processor for DI (#1704)

This commit is contained in:
Guillaume Nodet 2024-09-10 19:18:47 +02:00 committed by GitHub
parent 96b12394bf
commit 8a61f7d20a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 138 additions and 173 deletions

View File

@ -30,4 +30,7 @@
<name>Maven 4 API :: Dependency Injection</name>
<description>Maven 4 API - Dependency Injection</description>
<properties>
<maven.compiler.proc>none</maven.compiler.proc>
</properties>
</project>

View File

@ -0,0 +1,95 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.di.tool;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic;
import javax.tools.FileObject;
import javax.tools.StandardLocation;
import java.io.IOException;
import java.io.Writer;
import java.util.Set;
import org.apache.maven.api.di.Named;
// Auto-register the annotation processor
@SupportedAnnotationTypes("org.apache.maven.api.di.Named")
@SupportedSourceVersion(SourceVersion.RELEASE_17)
public class DiIndexProcessor extends AbstractProcessor {
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
// Collect the fully qualified names of classes annotated with @Named
StringBuilder builder = new StringBuilder();
processingEnv
.getMessager()
.printMessage(
Diagnostic.Kind.NOTE,
"Processing " + roundEnv.getRootElements().size() + " classes");
for (Element element : roundEnv.getElementsAnnotatedWith(Named.class)) {
if (element instanceof TypeElement typeElement) {
// Get the fully qualified class name
String className = typeElement.getQualifiedName().toString();
// Handle inner classes by checking if the enclosing element is a class or interface
Element enclosingElement = typeElement.getEnclosingElement();
if (enclosingElement instanceof TypeElement) {
// It's an inner class, replace the last dot with a '$'
String enclosingClassName =
((TypeElement) enclosingElement).getQualifiedName().toString();
className = enclosingClassName + "$" + typeElement.getSimpleName();
}
builder.append(className).append("\n");
}
}
if (!builder.isEmpty()) { // Check if the StringBuilder is non-empty
try {
writeFile(builder.toString());
} catch (IOException e) {
processingEnv
.getMessager()
.printMessage(Diagnostic.Kind.ERROR, "Error writing file: " + e.getMessage());
}
}
return true; // Indicate that annotations are claimed by this processor
}
private void writeFile(String content) throws IOException {
// Create the file META-INF/maven/org.apache.maven.api.di.Inject
FileObject fileObject = processingEnv
.getFiler()
.createResource(StandardLocation.CLASS_OUTPUT, "", "META-INF/maven/org.apache.maven.api.di.Inject");
try (Writer writer = fileObject.openWriter()) {
writer.write(content);
}
}
}

View File

@ -0,0 +1 @@
org.apache.maven.di.tool.DiIndexProcessor

View File

@ -43,6 +43,10 @@
<groupId>org.apache.maven</groupId>
<artifactId>maven-api-core</artifactId>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-api-di</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -21,10 +21,12 @@ package org.apache.maven.api.spi;
import org.apache.maven.api.Language;
import org.apache.maven.api.annotations.Consumer;
import org.apache.maven.api.annotations.Experimental;
import org.apache.maven.api.di.Named;
/**
* @since 4.0.0
*/
@Experimental
@Consumer
@Named
public interface LanguageProvider extends ExtensibleEnumProvider<Language> {}

View File

@ -21,7 +21,9 @@ package org.apache.maven.api.spi;
import org.apache.maven.api.Lifecycle;
import org.apache.maven.api.annotations.Consumer;
import org.apache.maven.api.annotations.Experimental;
import org.apache.maven.api.di.Named;
@Experimental
@Consumer
@Named
public interface LifecycleProvider extends ExtensibleEnumProvider<Lifecycle> {}

View File

@ -26,6 +26,7 @@ import org.apache.maven.api.annotations.Consumer;
import org.apache.maven.api.annotations.Experimental;
import org.apache.maven.api.annotations.Nonnull;
import org.apache.maven.api.annotations.Nullable;
import org.apache.maven.api.di.Named;
import org.apache.maven.api.model.Model;
import org.apache.maven.api.services.Source;
@ -37,6 +38,7 @@ import org.apache.maven.api.services.Source;
*/
@Experimental
@Consumer
@Named
public interface ModelParser extends SpiService {
/**

View File

@ -21,7 +21,9 @@ package org.apache.maven.api.spi;
import org.apache.maven.api.Packaging;
import org.apache.maven.api.annotations.Consumer;
import org.apache.maven.api.annotations.Experimental;
import org.apache.maven.api.di.Named;
@Experimental
@Consumer
@Named
public interface PackagingProvider extends ExtensibleEnumProvider<Packaging> {}

View File

@ -21,10 +21,12 @@ package org.apache.maven.api.spi;
import org.apache.maven.api.PathScope;
import org.apache.maven.api.annotations.Consumer;
import org.apache.maven.api.annotations.Experimental;
import org.apache.maven.api.di.Named;
/**
* @since 4.0.0
*/
@Experimental
@Consumer
@Named
public interface PathScopeProvider extends ExtensibleEnumProvider<PathScope> {}

View File

@ -21,10 +21,12 @@ package org.apache.maven.api.spi;
import org.apache.maven.api.ProjectScope;
import org.apache.maven.api.annotations.Consumer;
import org.apache.maven.api.annotations.Experimental;
import org.apache.maven.api.di.Named;
/**
* @since 4.0.0
*/
@Experimental
@Consumer
@Named
public interface ProjectScopeProvider extends ExtensibleEnumProvider<ProjectScope> {}

View File

@ -22,6 +22,7 @@ import java.util.Map;
import org.apache.maven.api.annotations.Consumer;
import org.apache.maven.api.annotations.Experimental;
import org.apache.maven.api.di.Named;
/**
* Component able to contribute to Maven session user properties. This SPI component is invoked
@ -31,6 +32,7 @@ import org.apache.maven.api.annotations.Experimental;
*/
@Experimental
@Consumer
@Named
public interface PropertyContributor extends SpiService {
/**
* Invoked just before session is created with a mutable map that carries collected user properties so far.

View File

@ -21,10 +21,12 @@ package org.apache.maven.api.spi;
import org.apache.maven.api.Type;
import org.apache.maven.api.annotations.Consumer;
import org.apache.maven.api.annotations.Experimental;
import org.apache.maven.api.di.Named;
/**
* @since 4.0.0
*/
@Experimental
@Consumer
@Named
public interface TypeProvider extends ExtensibleEnumProvider<Type> {}

View File

@ -51,61 +51,13 @@ import org.apache.maven.api.services.PackagingRegistry;
import org.apache.maven.api.services.RepositoryFactory;
import org.apache.maven.api.services.SettingsBuilder;
import org.apache.maven.api.services.TypeRegistry;
import org.apache.maven.api.services.model.ProfileActivator;
import org.apache.maven.api.settings.Settings;
import org.apache.maven.api.spi.ModelParser;
import org.apache.maven.api.spi.TypeProvider;
import org.apache.maven.di.Injector;
import org.apache.maven.di.Key;
import org.apache.maven.di.impl.DIException;
import org.apache.maven.internal.impl.AbstractSession;
import org.apache.maven.internal.impl.DefaultArtifactCoordinatesFactory;
import org.apache.maven.internal.impl.DefaultArtifactDeployer;
import org.apache.maven.internal.impl.DefaultArtifactFactory;
import org.apache.maven.internal.impl.DefaultArtifactInstaller;
import org.apache.maven.internal.impl.DefaultArtifactResolver;
import org.apache.maven.internal.impl.DefaultChecksumAlgorithmService;
import org.apache.maven.internal.impl.DefaultDependencyCoordinatesFactory;
import org.apache.maven.internal.impl.DefaultDependencyResolver;
import org.apache.maven.internal.impl.DefaultLocalRepositoryManager;
import org.apache.maven.internal.impl.DefaultMessageBuilderFactory;
import org.apache.maven.internal.impl.DefaultModelUrlNormalizer;
import org.apache.maven.internal.impl.DefaultModelVersionParser;
import org.apache.maven.internal.impl.DefaultModelXmlFactory;
import org.apache.maven.internal.impl.DefaultPluginConfigurationExpander;
import org.apache.maven.internal.impl.DefaultRepositoryFactory;
import org.apache.maven.internal.impl.DefaultSettingsBuilder;
import org.apache.maven.internal.impl.DefaultSettingsXmlFactory;
import org.apache.maven.internal.impl.DefaultSuperPomProvider;
import org.apache.maven.internal.impl.DefaultToolchainsBuilder;
import org.apache.maven.internal.impl.DefaultToolchainsXmlFactory;
import org.apache.maven.internal.impl.DefaultTransportProvider;
import org.apache.maven.internal.impl.DefaultUrlNormalizer;
import org.apache.maven.internal.impl.DefaultVersionParser;
import org.apache.maven.internal.impl.ExtensibleEnumRegistries;
import org.apache.maven.internal.impl.InternalSession;
import org.apache.maven.internal.impl.model.BuildModelTransformer;
import org.apache.maven.internal.impl.model.DefaultDependencyManagementImporter;
import org.apache.maven.internal.impl.model.DefaultDependencyManagementInjector;
import org.apache.maven.internal.impl.model.DefaultInheritanceAssembler;
import org.apache.maven.internal.impl.model.DefaultLifecycleBindingsInjector;
import org.apache.maven.internal.impl.model.DefaultModelBuilder;
import org.apache.maven.internal.impl.model.DefaultModelInterpolator;
import org.apache.maven.internal.impl.model.DefaultModelNormalizer;
import org.apache.maven.internal.impl.model.DefaultModelPathTranslator;
import org.apache.maven.internal.impl.model.DefaultModelProcessor;
import org.apache.maven.internal.impl.model.DefaultModelValidator;
import org.apache.maven.internal.impl.model.DefaultModelVersionProcessor;
import org.apache.maven.internal.impl.model.DefaultPathTranslator;
import org.apache.maven.internal.impl.model.DefaultPluginManagementInjector;
import org.apache.maven.internal.impl.model.DefaultProfileInjector;
import org.apache.maven.internal.impl.model.DefaultProfileSelector;
import org.apache.maven.internal.impl.model.DefaultRootLocator;
import org.apache.maven.internal.impl.model.ProfileActivationFilePathInterpolator;
import org.apache.maven.internal.impl.resolver.DefaultVersionRangeResolver;
import org.apache.maven.internal.impl.resolver.DefaultVersionResolver;
import org.apache.maven.internal.impl.resolver.MavenVersionScheme;
import org.apache.maven.internal.impl.resolver.type.DefaultTypeProvider;
import org.eclipse.aether.DefaultRepositorySystemSession;
import org.eclipse.aether.RepositorySystem;
import org.eclipse.aether.RepositorySystemSession;
@ -122,66 +74,14 @@ public class ApiRunner {
Injector injector = Injector.create();
injector.bindInstance(Injector.class, injector);
injector.bindImplicit(ApiRunner.class);
injector.bindImplicit(DefaultArtifactCoordinatesFactory.class);
injector.bindImplicit(DefaultArtifactDeployer.class);
injector.bindImplicit(DefaultArtifactFactory.class);
injector.bindImplicit(DefaultArtifactInstaller.class);
injector.bindImplicit(DefaultArtifactResolver.class);
injector.bindImplicit(DefaultChecksumAlgorithmService.class);
injector.bindImplicit(DefaultDependencyResolver.class);
injector.bindImplicit(DefaultDependencyCoordinatesFactory.class);
injector.bindImplicit(DefaultLocalRepositoryManager.class);
injector.bindImplicit(DefaultMessageBuilderFactory.class);
injector.bindImplicit(DefaultModelXmlFactory.class);
injector.bindImplicit(DefaultRepositoryFactory.class);
injector.bindImplicit(DefaultSettingsBuilder.class);
injector.bindImplicit(DefaultSettingsXmlFactory.class);
injector.bindImplicit(DefaultToolchainsBuilder.class);
injector.bindImplicit(DefaultToolchainsXmlFactory.class);
injector.bindImplicit(DefaultTransportProvider.class);
injector.bindImplicit(DefaultVersionParser.class);
injector.bindImplicit(DefaultVersionRangeResolver.class);
injector.bindImplicit(org.apache.maven.internal.impl.DefaultVersionParser.class);
injector.bindImplicit(org.apache.maven.internal.impl.DefaultVersionRangeResolver.class);
injector.bindImplicit(DefaultVersionResolver.class);
injector.bindImplicit(ExtensibleEnumRegistries.class);
injector.bindImplicit(DefaultTypeProvider.class);
injector.bindImplicit(MavenVersionScheme.class);
injector.bindImplicit(BuildModelTransformer.class);
injector.bindImplicit(DefaultDependencyManagementImporter.class);
injector.bindImplicit(DefaultDependencyManagementInjector.class);
injector.bindImplicit(DefaultModelBuilder.class);
injector.bindImplicit(DefaultModelProcessor.class);
injector.bindImplicit(DefaultModelValidator.class);
injector.bindImplicit(DefaultModelVersionProcessor.class);
injector.bindImplicit(DefaultModelNormalizer.class);
injector.bindImplicit(DefaultModelInterpolator.class);
injector.bindImplicit(DefaultPathTranslator.class);
injector.bindImplicit(DefaultRootLocator.class);
injector.bindImplicit(DefaultModelPathTranslator.class);
injector.bindImplicit(DefaultUrlNormalizer.class);
injector.bindImplicit(DefaultModelUrlNormalizer.class);
injector.bindImplicit(DefaultSuperPomProvider.class);
injector.bindImplicit(DefaultInheritanceAssembler.class);
injector.bindImplicit(DefaultProfileInjector.class);
injector.bindImplicit(DefaultProfileSelector.class);
injector.bindImplicit(DefaultPluginManagementInjector.class);
injector.bindImplicit(DefaultLifecycleBindingsInjector.class);
injector.bindImplicit(DefaultPluginConfigurationExpander.class);
injector.bindImplicit(ProfileActivationFilePathInterpolator.class);
injector.bindImplicit(DefaultModelVersionParser.class);
injector.bindImplicit(ProfileActivator.class);
injector.bindImplicit(ModelParser.class);
injector.discover(ApiRunner.class.getClassLoader());
return injector.getInstance(Session.class);
}
static class DefaultSession extends AbstractSession {
private final Map<String, String> systemProperties;
private Instant startTime = Instant.now();
private final Instant startTime = Instant.now();
DefaultSession(RepositorySystemSession session, RepositorySystem repositorySystem, Lookup lookup) {
this(session, repositorySystem, Collections.emptyList(), null, lookup);
@ -195,7 +95,7 @@ public class ApiRunner {
Lookup lookup) {
super(session, repositorySystem, repositories, resolverRepositories, lookup);
systemProperties = System.getenv().entrySet().stream()
.collect(Collectors.toMap(e -> "env." + e.getKey(), e -> e.getValue()));
.collect(Collectors.toMap(e -> "env." + e.getKey(), Map.Entry::getValue));
System.getProperties().forEach((k, v) -> systemProperties.put(k.toString(), v.toString()));
}
@ -266,6 +166,7 @@ public class ApiRunner {
}
@Provides
@SuppressWarnings("unused")
static Lookup newLookup(Injector injector) {
return new Lookup() {
@Override
@ -317,6 +218,7 @@ public class ApiRunner {
}
@Provides
@SuppressWarnings("unused")
static ArtifactManager newArtifactManager() {
return new ArtifactManager() {
private final Map<Artifact, Path> paths = new ConcurrentHashMap<>();
@ -334,11 +236,13 @@ public class ApiRunner {
}
@Provides
@SuppressWarnings("unused")
static PackagingRegistry newPackagingRegistry(TypeRegistry typeRegistry) {
return id -> Optional.of(new DumbPackaging(id, typeRegistry.require(id), Map.of()));
}
@Provides
@SuppressWarnings("unused")
static TypeRegistry newTypeRegistry(List<TypeProvider> providers) {
return new TypeRegistry() {
@Override
@ -352,6 +256,7 @@ public class ApiRunner {
}
@Provides
@SuppressWarnings("unused")
static LifecycleRegistry newLifecycleRegistry() {
return new LifecycleRegistry() {
@ -373,21 +278,25 @@ public class ApiRunner {
}
@Provides
@SuppressWarnings("unused")
static RepositorySystemSupplier newRepositorySystemSupplier() {
return new RepositorySystemSupplier();
}
@Provides
@SuppressWarnings("unused")
static RepositorySystem newRepositorySystem(RepositorySystemSupplier repositorySystemSupplier) {
return repositorySystemSupplier.getRepositorySystem();
}
@Provides
@SuppressWarnings("unused")
static RemoteRepositoryManager newRemoteRepositoryManager(RepositorySystemSupplier repositorySystemSupplier) {
return repositorySystemSupplier.getRemoteRepositoryManager();
}
@Provides
@SuppressWarnings("unused")
static Session newSession(RepositorySystem system, Lookup lookup) {
Map<String, String> properties = new HashMap<>();
// Env variables prefixed with "env."

View File

@ -1,70 +0,0 @@
org.apache.maven.api.services.model.ProfileActivator
org.apache.maven.api.spi.LanguageProvider
org.apache.maven.api.spi.LifecycleProvider
org.apache.maven.api.spi.ModelParser
org.apache.maven.api.spi.PackagingProvider
org.apache.maven.internal.aether.DefaultRepositorySystemSessionFactory
org.apache.maven.internal.aether.LegacyRepositorySystemSessionExtender
org.apache.maven.internal.impl.DefaultArtifactCoordinatesFactory
org.apache.maven.internal.impl.DefaultArtifactDeployer
org.apache.maven.internal.impl.DefaultArtifactFactory
org.apache.maven.internal.impl.DefaultArtifactInstaller
org.apache.maven.internal.impl.DefaultArtifactResolver
org.apache.maven.internal.impl.DefaultChecksumAlgorithmService
org.apache.maven.internal.impl.DefaultDependencyCoordinatesFactory
org.apache.maven.internal.impl.DefaultDependencyResolver
org.apache.maven.internal.impl.DefaultLocalRepositoryManager
org.apache.maven.internal.impl.DefaultMessageBuilderFactory
org.apache.maven.internal.impl.DefaultModelUrlNormalizer
org.apache.maven.internal.impl.DefaultModelVersionParser
org.apache.maven.internal.impl.DefaultModelXmlFactory
org.apache.maven.internal.impl.DefaultPluginConfigurationExpander
org.apache.maven.internal.impl.DefaultRepositoryFactory
org.apache.maven.internal.impl.DefaultSettingsBuilder
org.apache.maven.internal.impl.DefaultSettingsXmlFactory
org.apache.maven.internal.impl.DefaultSuperPomProvider
org.apache.maven.internal.impl.DefaultToolchainsBuilder
org.apache.maven.internal.impl.DefaultToolchainsXmlFactory
org.apache.maven.internal.impl.DefaultTransportProvider
org.apache.maven.internal.impl.DefaultUrlNormalizer
org.apache.maven.internal.impl.DefaultVersionParser
org.apache.maven.internal.impl.DefaultVersionRangeResolver
org.apache.maven.internal.impl.DefaultVersionResolver
org.apache.maven.internal.impl.ExtensibleEnumRegistries$DefaultLanguageRegistry
org.apache.maven.internal.impl.ExtensibleEnumRegistries$DefaultPathScopeRegistry
org.apache.maven.internal.impl.ExtensibleEnumRegistries$DefaultProjectScopeRegistry
org.apache.maven.internal.impl.model.BuildModelTransformer
org.apache.maven.internal.impl.model.DefaultDependencyManagementImporter
org.apache.maven.internal.impl.model.DefaultDependencyManagementInjector
org.apache.maven.internal.impl.model.DefaultInheritanceAssembler
org.apache.maven.internal.impl.model.DefaultLifecycleBindingsInjector
org.apache.maven.internal.impl.model.DefaultModelBuilder
org.apache.maven.internal.impl.model.DefaultModelInterpolator
org.apache.maven.internal.impl.model.DefaultModelNormalizer
org.apache.maven.internal.impl.model.DefaultModelPathTranslator
org.apache.maven.internal.impl.model.DefaultModelProcessor
org.apache.maven.internal.impl.model.DefaultModelValidator
org.apache.maven.internal.impl.model.DefaultModelVersionProcessor
org.apache.maven.internal.impl.model.DefaultPathTranslator
org.apache.maven.internal.impl.model.DefaultPluginManagementInjector
org.apache.maven.internal.impl.model.DefaultProfileInjector
org.apache.maven.internal.impl.model.DefaultProfileSelector
org.apache.maven.internal.impl.model.DefaultRootLocator
org.apache.maven.internal.impl.model.ProfileActivationFilePathInterpolator
org.apache.maven.internal.impl.model.profile.FileProfileActivator
org.apache.maven.internal.impl.model.profile.JdkVersionProfileActivator
org.apache.maven.internal.impl.model.profile.OperatingSystemProfileActivator
org.apache.maven.internal.impl.model.profile.PackagingProfileActivator
org.apache.maven.internal.impl.model.profile.PropertyProfileActivator
org.apache.maven.internal.impl.resolver.DefaultArtifactDescriptorReader
org.apache.maven.internal.impl.resolver.DefaultArtifactDescriptorReader
org.apache.maven.internal.impl.resolver.DefaultModelResolver
org.apache.maven.internal.impl.resolver.DefaultVersionRangeResolver
org.apache.maven.internal.impl.resolver.DefaultVersionResolver
org.apache.maven.internal.impl.resolver.MavenVersionScheme
org.apache.maven.internal.impl.resolver.PluginsMetadataGeneratorFactory
org.apache.maven.internal.impl.resolver.SnapshotMetadataGeneratorFactory
org.apache.maven.internal.impl.resolver.VersionsMetadataGeneratorFactory
org.apache.maven.internal.impl.resolver.relocation.DistributionManagementArtifactRelocationSource
org.apache.maven.internal.impl.resolver.relocation.UserPropertiesArtifactRelocationSource
org.apache.maven.internal.impl.resolver.type.DefaultTypeProvider

View File

@ -123,6 +123,9 @@ public class InjectorImpl implements Injector {
Key<?> key = Key.of(clazz, ReflectionUtils.qualifierOf(clazz));
if (clazz.isInterface()) {
bindings.computeIfAbsent(key, $ -> new HashSet<>());
if (key.getQualifier() != null) {
bindings.computeIfAbsent(Key.ofType(clazz), $ -> new HashSet<>());
}
} else if (!Modifier.isAbstract(clazz.getModifiers())) {
Binding<?> binding = ReflectionUtils.generateImplicitBinding(key);
doBind(key, binding);
@ -143,6 +146,9 @@ public class InjectorImpl implements Injector {
while (cls != Object.class && cls != null) {
key = Key.of(cls, key.getQualifier());
doBindImplicit(key, binding);
if (key.getQualifier() != null) {
bind(Key.ofType(key.getType()), binding);
}
cls = cls.getSuperclass();
}
return this;

View File

@ -153,6 +153,7 @@ under the License.
<maven.compiler.source>${javaVersion}</maven.compiler.source>
<maven.compiler.target>${javaVersion}</maven.compiler.target>
<maven.compiler.release>${javaVersion}</maven.compiler.release>
<maven.compiler.proc>full</maven.compiler.proc>
<maven.test.redirectTestOutputToFile>true</maven.test.redirectTestOutputToFile>
<maven.baseline>3.8.8</maven.baseline>
<!-- Control the name of the distribution and information output by mvn -->