diff --git a/.github/workflows/maven-verify.yml b/.github/workflows/maven-verify.yml index 932827cf9..89d9cfdbc 100644 --- a/.github/workflows/maven-verify.yml +++ b/.github/workflows/maven-verify.yml @@ -25,3 +25,8 @@ jobs: build: name: Verify uses: apache/maven-gh-actions-shared/.github/workflows/maven-verify.yml@v4 + with: + maven-matrix: '[ "3.6.3", "3.9.7", "4.0.0-beta-3" ]' + jdk-matrix: '[ "8", "17", "21" ]' + matrix-exclude: '[ { maven: "4.0.0-beta-3", jdk: "8" } ]' + diff --git a/maven-plugin-plugin/src/it/v4api/invoker.properties b/maven-plugin-plugin/src/it/v4api/invoker.properties index 43be5b1d2..e573acf3e 100644 --- a/maven-plugin-plugin/src/it/v4api/invoker.properties +++ b/maven-plugin-plugin/src/it/v4api/invoker.properties @@ -15,4 +15,6 @@ # specific language governing permissions and limitations # under the License. +invoker.java.version = 17+ invoker.goals.1 = clean install +invoker.goals.2 = org.apache.maven.its:v4api:1.0-SNAPSHOT:first \ No newline at end of file diff --git a/maven-plugin-plugin/src/it/v4api/src/main/java/org/apache/maven/its/v4api/FirstMojo.java b/maven-plugin-plugin/src/it/v4api/src/main/java/org/apache/maven/its/v4api/FirstMojo.java index 879f3cefa..7ca1a4be9 100644 --- a/maven-plugin-plugin/src/it/v4api/src/main/java/org/apache/maven/its/v4api/FirstMojo.java +++ b/maven-plugin-plugin/src/it/v4api/src/main/java/org/apache/maven/its/v4api/FirstMojo.java @@ -19,34 +19,27 @@ package org.apache.maven.its.v4api; import java.nio.file.Path; +import java.util.List; import org.apache.maven.api.MojoExecution; import org.apache.maven.api.Project; -import org.apache.maven.api.ResolutionScope; 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.MojoException; -import org.apache.maven.api.plugin.annotations.Component; -import org.apache.maven.api.plugin.annotations.Execute; -import org.apache.maven.api.plugin.annotations.LifecyclePhase; import org.apache.maven.api.plugin.annotations.Mojo; import org.apache.maven.api.plugin.annotations.Parameter; -import org.apache.maven.api.services.ArtifactInstaller; -import org.apache.maven.api.settings.Settings; +import org.apache.maven.api.plugin.annotations.Resolution; /** * Test mojo for the v4 api plugin descriptor generation. * This mojo is not actually runnable because: * - it's using a custom lifecycle which is not defined - * - it has a @Component dependency on ArtifactInstaller (hint=test) which does not exist + * - it has a @Inject dependency on ArtifactInstaller (hint=test) which does not exist * * @since 1.2 */ -@Mojo( - name = "first", - requiresDependencyResolution = ResolutionScope.TEST, - defaultPhase = LifecyclePhase.INTEGRATION_TEST) -@Execute(phase = LifecyclePhase.GENERATE_SOURCES, lifecycle = "cobertura") +@Mojo(name = "first", defaultPhase = "integration-test") public class FirstMojo implements org.apache.maven.api.plugin.Mojo { /** @@ -66,23 +59,25 @@ public class FirstMojo implements org.apache.maven.api.plugin.Mojo { @Parameter(name = "namedParam", alias = "alias") private String aliasedParam; - @Component + @Resolution(pathScope = "main-runtime") + private List classPath; + + @Inject private Session session; - @Component + @Inject private Project project; - @Component + @Inject private MojoExecution mojo; - @Component - private Settings settings; - - @Component + @Inject private Log log; - @Component(role = ArtifactInstaller.class, hint = "test") - private Object custom; - - public void execute() throws MojoException {} + public void execute() throws MojoException { + log.info("Executing first"); + for (Path path : classPath) { + log.info(path.toString()); + } + } } diff --git a/maven-plugin-plugin/src/it/v4api/verify.groovy b/maven-plugin-plugin/src/it/v4api/verify.groovy index 1405e2313..2d5c38f00 100644 --- a/maven-plugin-plugin/src/it/v4api/verify.groovy +++ b/maven-plugin-plugin/src/it/v4api/verify.groovy @@ -24,8 +24,8 @@ assert descriptorFile.isFile() def pluginDescriptor = new XmlParser().parse( descriptorFile ); -assert pluginDescriptor.requiredJavaVersion.text() == '1.8' -assert pluginDescriptor.requiredMavenVersion.text() == '4.0.0-alpha-4' +assert pluginDescriptor.requiredJavaVersion.text() == '17' +assert pluginDescriptor.requiredMavenVersion.text() == '4.0.0-beta-4-SNAPSHOT' def mojo = pluginDescriptor.mojos.mojo.findAll{ it.goal.text() == "first" }[0] @@ -33,51 +33,10 @@ assert mojo.goal.text() == 'first' assert mojo.implementation.text() == 'org.apache.maven.its.v4api.FirstMojo' assert mojo.language.text() == 'java' assert mojo.description.text().startsWith('Test mojo for the v4 api plugin descriptor generation.') -assert mojo.requiresDependencyResolution.text() == 'test' -assert mojo.requiresDependencyCollection.text() == '' -assert mojo.requiresProject.text() == 'true' -assert mojo.requiresOnline.text() == 'false' -assert mojo.requiresDirectInvocation.text() == 'false' +assert mojo.projectRequired.text() == 'true' +assert mojo.onlineRequired.text() == 'false' assert mojo.aggregator.text() == 'false' -assert mojo.threadSafe.text() == 'false' assert mojo.phase.text() == 'integration-test' -assert mojo.executePhase.text() == 'generate-sources' -assert mojo.executeLifecycle.text() == 'cobertura' -assert mojo.v4Api.text() == 'true' - -assert mojo.configuration.basedir[0].text() == '' -assert mojo.configuration.basedir[0].'@implementation' == 'java.nio.file.Path' -assert mojo.configuration.basedir[0].'@default-value' == '${basedir}' - -assert mojo.configuration.touchFile[0].text() == '${first.touchFile}' -assert mojo.configuration.touchFile[0].'@implementation' == 'java.nio.file.Path' -assert mojo.configuration.touchFile[0].'@default-value' == '${project.build.directory}/touch.txt' - -assert mojo.requirements.requirement.size() == 6 - -assert mojo.requirements.requirement[0].role.text() == 'org.apache.maven.api.services.ArtifactInstaller' -assert mojo.requirements.requirement[0].'role-hint'.text() == 'test' -assert mojo.requirements.requirement[0].'field-name'.text() == 'custom' - -assert mojo.requirements.requirement[1].role.text() == 'org.apache.maven.api.plugin.Log' -assert mojo.requirements.requirement[1].'role-hint'.isEmpty() -assert mojo.requirements.requirement[1].'field-name'.text() == 'log' - -assert mojo.requirements.requirement[2].role.text() == 'org.apache.maven.api.MojoExecution' -assert mojo.requirements.requirement[2].'role-hint'.isEmpty() -assert mojo.requirements.requirement[2].'field-name'.text() == 'mojo' - -assert mojo.requirements.requirement[3].role.text() == 'org.apache.maven.api.Project' -assert mojo.requirements.requirement[3].'role-hint'.isEmpty() -assert mojo.requirements.requirement[3].'field-name'.text() == 'project' - -assert mojo.requirements.requirement[4].role.text() == 'org.apache.maven.api.Session' -assert mojo.requirements.requirement[4].'role-hint'.isEmpty() -assert mojo.requirements.requirement[4].'field-name'.text() == 'session' - -assert mojo.requirements.requirement[5].role.text() == 'org.apache.maven.api.settings.Settings' -assert mojo.requirements.requirement[5].'role-hint'.isEmpty() -assert mojo.requirements.requirement[5].'field-name'.text() == 'settings' assert mojo.parameters.parameter.size() == 3 @@ -90,6 +49,8 @@ assert parameter.deprecated.isEmpty() assert parameter.required.text() == 'false' assert parameter.editable.text() == 'false' assert parameter.description.text() == 'Project directory.' +assert parameter.defaultValue.text() == '${basedir}' +assert parameter.expression.isEmpty() parameter = mojo.parameters.parameter.findAll{ it.name.text() == "touchFile" }[0] assert parameter.name.text() == 'touchFile' @@ -100,6 +61,8 @@ assert parameter.deprecated.isEmpty() assert parameter.required.text() == 'true' assert parameter.editable.text() == 'true' assert parameter.description.text() == '' +assert parameter.defaultValue.text() == '${project.build.directory}/touch.txt' +assert parameter.expression.text() == '${first.touchFile}' parameter = mojo.parameters.parameter.findAll{ it.name.text() == "namedParam" }[0] assert parameter.name.text() == 'namedParam' @@ -110,6 +73,15 @@ assert parameter.deprecated.text() == 'As of 0.2' assert parameter.required.text() == 'false' assert parameter.editable.text() == 'true' assert parameter.description.text() == '' +assert parameter.defaultValue.isEmpty() +assert parameter.expression.isEmpty() + +assert mojo.resolutions.resolution.size() == 1 + +resolution = mojo.resolutions.resolution[0] +assert resolution.field.text() == 'classPath' +assert resolution.pathScope.text() == 'main-runtime' +assert resolution.requestType.text() == '' // check help mojo source and class assert new File( basedir, "target/classes/org/apache/maven/its/v4api/HelpMojo.class" ).isFile() diff --git a/maven-plugin-plugin/src/main/java/org/apache/maven/plugin/plugin/DescriptorGeneratorMojo.java b/maven-plugin-plugin/src/main/java/org/apache/maven/plugin/plugin/DescriptorGeneratorMojo.java index 862edeaec..73a0e5613 100644 --- a/maven-plugin-plugin/src/main/java/org/apache/maven/plugin/plugin/DescriptorGeneratorMojo.java +++ b/maven-plugin-plugin/src/main/java/org/apache/maven/plugin/plugin/DescriptorGeneratorMojo.java @@ -19,12 +19,16 @@ package org.apache.maven.plugin.plugin; import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; import java.net.URI; -import java.util.Arrays; -import java.util.Collections; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Set; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.resolver.filter.ArtifactFilter; @@ -32,6 +36,7 @@ import org.apache.maven.execution.MavenSession; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.descriptor.InvalidPluginDescriptorException; +import org.apache.maven.plugin.descriptor.MojoDescriptor; import org.apache.maven.plugin.descriptor.PluginDescriptor; import org.apache.maven.plugins.annotations.Component; import org.apache.maven.plugins.annotations.LifecyclePhase; @@ -39,6 +44,7 @@ import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.plugins.annotations.ResolutionScope; import org.apache.maven.tools.plugin.DefaultPluginToolsRequest; +import org.apache.maven.tools.plugin.ExtendedMojoDescriptor; import org.apache.maven.tools.plugin.ExtendedPluginDescriptor; import org.apache.maven.tools.plugin.PluginToolsRequest; import org.apache.maven.tools.plugin.extractor.ExtractionException; @@ -48,8 +54,14 @@ import org.apache.maven.tools.plugin.scanner.MojoScanner; import org.codehaus.plexus.component.repository.ComponentDependency; import org.codehaus.plexus.util.ReaderFactory; +import org.codehaus.plexus.util.io.CachingOutputStream; +import org.codehaus.plexus.util.io.CachingWriter; +import org.objectweb.asm.*; import org.sonatype.plexus.build.incremental.BuildContext; +import static org.objectweb.asm.Opcodes.*; +import static org.objectweb.asm.Opcodes.ACC_PUBLIC; + /** *

* Generate a plugin descriptor. @@ -78,6 +90,12 @@ public class DescriptorGeneratorMojo extends AbstractGeneratorMojo { @Parameter(defaultValue = "${project.build.outputDirectory}/META-INF/maven", readonly = true) private File outputDirectory; + /** + * The directory where the generated class files will be put. + */ + @Parameter(defaultValue = "${project.build.outputDirectory}", readonly = true) + private File classesOutputDirectory; + /** * The file encoding of the source files. * @@ -269,7 +287,6 @@ public class DescriptorGeneratorMojo extends AbstractGeneratorMojo { protected BuildContext buildContext; public void generate() throws MojoExecutionException { - if (!"maven-plugin".equalsIgnoreCase(project.getArtifactId()) && project.getArtifactId().toLowerCase().startsWith("maven-") && project.getArtifactId().toLowerCase().endsWith("-plugin") @@ -352,6 +369,12 @@ public void generate() throws MojoExecutionException { PluginDescriptorFilesGenerator pluginDescriptorGenerator = new PluginDescriptorFilesGenerator(); pluginDescriptorGenerator.execute(outputDirectory, request); + // Generate the additional factories for v4 mojos + generateFactories(request.getPluginDescriptor()); + + // Generate index for v4 beans + generateIndex(); + buildContext.refresh(outputDirectory); } catch (GeneratorException e) { throw new MojoExecutionException("Error writing plugin descriptor", e); @@ -367,6 +390,128 @@ public void generate() throws MojoExecutionException { } } + private void generateIndex() throws GeneratorException { + try { + Set diBeans = new TreeSet<>(); + try (Stream paths = Files.walk(classesOutputDirectory.toPath())) { + List classes = paths.filter( + p -> p.getFileName().toString().endsWith(".class")) + .collect(Collectors.toList()); + for (Path classFile : classes) { + String fileString = classFile.toString(); + String className = fileString + .substring(0, fileString.length() - ".class".length()) + .replace('/', '.'); + try (InputStream is = Files.newInputStream(classFile)) { + ClassReader rdr = new ClassReader(is); + rdr.accept( + new ClassVisitor(Opcodes.ASM9) { + String className; + + @Override + public void visit( + int version, + int access, + String name, + String signature, + String superName, + String[] interfaces) { + super.visit(version, access, name, signature, superName, interfaces); + className = name; + } + + @Override + public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) { + if ("Lorg/apache/maven/api/di/Named;".equals(descriptor)) { + diBeans.add(className.replace('/', '.')); + } + return null; + } + }, + ClassReader.SKIP_FRAMES | ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG); + } + + // Class clazz = project.getClassRealm().loadClass(className); + // boolean hasQualifier = Stream.of(clazz.getAnnotations()) + // .flatMap(ann -> Stream.of(ann.getClass().getAnnotations())) + // .anyMatch(ann -> "org.apache.maven.api.di.Qualifier" + // .equals(ann.annotationType().getName())); + // if (hasQualifier) { + // diBeans.add(className); + // } + } + } + Path path = outputDirectory.toPath().resolve("org.apache.maven.api.di.Inject"); + if (diBeans.isEmpty()) { + Files.deleteIfExists(path); + } else { + String nl = System.lineSeparator(); + try (CachingWriter w = new CachingWriter(path, StandardCharsets.UTF_8)) { + String content = diBeans.stream().collect(Collectors.joining(nl, "", nl)); + w.write(content); + } + } + } catch (Exception e) { + throw new GeneratorException("Unable to generate index for v4 beans", e); + } + } + + private void generateFactories(PluginDescriptor pd) throws GeneratorException { + try { + for (MojoDescriptor md : pd.getMojos()) { + if (md instanceof ExtendedMojoDescriptor && ((ExtendedMojoDescriptor) md).isV4Api()) { + generateFactory(md); + } + } + } catch (IOException e) { + throw new GeneratorException("Unable to generate factories for v4 mojos", e); + } + } + + private void generateFactory(MojoDescriptor md) throws IOException { + String mojoClassName = md.getImplementation(); + String packageName = mojoClassName.substring(0, mojoClassName.lastIndexOf('.')); + String generatorClassName = mojoClassName.substring(mojoClassName.lastIndexOf('.') + 1) + "Factory"; + String mojoName = md.getId(); + + getLog().debug("Generating v4 factory for " + mojoClassName); + + byte[] bin = computeGeneratorClassBytes(packageName, generatorClassName, mojoName, mojoClassName); + + try (OutputStream os = new CachingOutputStream(classesOutputDirectory + .toPath() + .resolve(packageName.replace('.', '/') + "/" + generatorClassName + ".class"))) { + os.write(bin); + } + } + + static byte[] computeGeneratorClassBytes( + String packageName, String generatorClassName, String mojoName, String mojoClassName) { + String mojo = mojoClassName.replace('.', '/'); + ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); + cw.visitSource(generatorClassName + ".java", null); + AnnotationVisitor av = cw.visitAnnotation("Lorg/apache/maven/api/di/Named;", true); + av.visit("value", mojoName); + av.visitEnd(); + cw.visitAnnotation("Lorg/apache/maven/api/annotations/Generated;", true).visitEnd(); + cw.visit( + V1_8, + ACC_PUBLIC + ACC_SUPER + ACC_SYNTHETIC, + packageName.replace(".", "/") + "/" + generatorClassName, + null, + mojo, + null); + MethodVisitor mv = cw.visitMethod(ACC_PUBLIC + ACC_SYNTHETIC, "", "()V", null, null); + mv.visitCode(); + mv.visitVarInsn(Opcodes.ALOAD, 0); + mv.visitMethodInsn(Opcodes.INVOKESPECIAL, mojo, "", "()V", false); + mv.visitInsn(Opcodes.RETURN); + mv.visitMaxs(-1, -1); + mv.visitEnd(); + cw.visitEnd(); + return cw.toByteArray(); + } + private PluginDescriptor extendPluginDescriptor(PluginToolsRequest request) { ExtendedPluginDescriptor extendedPluginDescriptor = new ExtendedPluginDescriptor(request.getPluginDescriptor()); extendedPluginDescriptor.setRequiredJavaVersion(getRequiredJavaVersion(request)); diff --git a/maven-plugin-report-plugin/src/it/plugin-report-annotations/pom.xml b/maven-plugin-report-plugin/src/it/plugin-report-annotations/pom.xml index 1f355686d..3522d6abb 100644 --- a/maven-plugin-report-plugin/src/it/plugin-report-annotations/pom.xml +++ b/maven-plugin-report-plugin/src/it/plugin-report-annotations/pom.xml @@ -55,12 +55,6 @@ under the License. @maven3Version@ provided - - org.apache.maven.plugin-tools - maven-plugin-annotations - @project.version@ - provided - org.apache.maven.reporting maven-reporting-api diff --git a/maven-plugin-report-plugin/src/main/java/org/apache/maven/plugin/plugin/report/PluginReport.java b/maven-plugin-report-plugin/src/main/java/org/apache/maven/plugin/plugin/report/PluginReport.java index 5979fe700..6c747f4e6 100644 --- a/maven-plugin-report-plugin/src/main/java/org/apache/maven/plugin/plugin/report/PluginReport.java +++ b/maven-plugin-report-plugin/src/main/java/org/apache/maven/plugin/plugin/report/PluginReport.java @@ -35,13 +35,13 @@ import org.apache.maven.model.building.ModelBuildingRequest; import org.apache.maven.plugin.descriptor.MojoDescriptor; import org.apache.maven.plugin.descriptor.PluginDescriptor; -import org.apache.maven.plugin.descriptor.PluginDescriptorBuilder; import org.apache.maven.plugins.annotations.Component; import org.apache.maven.plugins.annotations.Execute; import org.apache.maven.plugins.annotations.LifecyclePhase; import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.plugins.plugin.descriptor.EnhancedPluginDescriptorBuilder; +import org.apache.maven.plugins.plugin.descriptor.PluginDescriptorBuilder; import org.apache.maven.project.DefaultProjectBuildingRequest; import org.apache.maven.project.MavenProject; import org.apache.maven.project.ProjectBuilder; diff --git a/maven-plugin-report-plugin/src/main/java/org/apache/maven/plugins/plugin/descriptor/EnhancedPluginDescriptorBuilder.java b/maven-plugin-report-plugin/src/main/java/org/apache/maven/plugins/plugin/descriptor/EnhancedPluginDescriptorBuilder.java index 2f29303a6..7c15b1b69 100644 --- a/maven-plugin-report-plugin/src/main/java/org/apache/maven/plugins/plugin/descriptor/EnhancedPluginDescriptorBuilder.java +++ b/maven-plugin-report-plugin/src/main/java/org/apache/maven/plugins/plugin/descriptor/EnhancedPluginDescriptorBuilder.java @@ -30,7 +30,6 @@ import org.apache.maven.plugin.descriptor.MojoDescriptor; import org.apache.maven.plugin.descriptor.Parameter; import org.apache.maven.plugin.descriptor.PluginDescriptor; -import org.apache.maven.plugin.descriptor.PluginDescriptorBuilder; import org.apache.maven.plugin.plugin.report.PluginReport; import org.apache.maven.rtinfo.RuntimeInformation; import org.apache.maven.tools.plugin.EnhancedParameterWrapper; diff --git a/maven-plugin-report-plugin/src/main/java/org/apache/maven/plugins/plugin/descriptor/PluginDescriptorBuilder.java b/maven-plugin-report-plugin/src/main/java/org/apache/maven/plugins/plugin/descriptor/PluginDescriptorBuilder.java new file mode 100644 index 000000000..037fdf6fd --- /dev/null +++ b/maven-plugin-report-plugin/src/main/java/org/apache/maven/plugins/plugin/descriptor/PluginDescriptorBuilder.java @@ -0,0 +1,325 @@ +/* + * 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.plugins.plugin.descriptor; + +import java.io.IOException; +import java.io.Reader; +import java.util.ArrayList; +import java.util.List; + +import org.apache.maven.plugin.descriptor.MojoDescriptor; +import org.apache.maven.plugin.descriptor.Parameter; +import org.apache.maven.plugin.descriptor.PluginDescriptor; +import org.codehaus.plexus.component.repository.ComponentDependency; +import org.codehaus.plexus.component.repository.ComponentRequirement; +import org.codehaus.plexus.configuration.PlexusConfiguration; +import org.codehaus.plexus.configuration.PlexusConfigurationException; +import org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration; +import org.codehaus.plexus.util.xml.Xpp3DomBuilder; +import org.codehaus.plexus.util.xml.pull.XmlPullParserException; + +/** + * Build plugin descriptor object from {@code plugin.xml}. + * + * @author Jason van Zyl + */ +public class PluginDescriptorBuilder { + public PluginDescriptor build(Reader reader) throws PlexusConfigurationException { + return build(reader, null); + } + + public PluginDescriptor build(Reader reader, String source) throws PlexusConfigurationException { + PlexusConfiguration c = buildConfiguration(reader); + + PluginDescriptor pluginDescriptor = new PluginDescriptor(); + + pluginDescriptor.setSource(source); + pluginDescriptor.setGroupId(c.getChild("groupId").getValue()); + pluginDescriptor.setArtifactId(c.getChild("artifactId").getValue()); + pluginDescriptor.setVersion(c.getChild("version").getValue()); + pluginDescriptor.setGoalPrefix(c.getChild("goalPrefix").getValue()); + + pluginDescriptor.setName(c.getChild("name").getValue()); + pluginDescriptor.setDescription(c.getChild("description").getValue()); + + String isolatedRealm = c.getChild("isolatedRealm").getValue(); + + if (isolatedRealm != null) { + pluginDescriptor.setIsolatedRealm(Boolean.parseBoolean(isolatedRealm)); + } + + String inheritedByDefault = c.getChild("inheritedByDefault").getValue(); + + if (inheritedByDefault != null) { + pluginDescriptor.setInheritedByDefault(Boolean.parseBoolean(inheritedByDefault)); + } + + // ---------------------------------------------------------------------- + // Components + // ---------------------------------------------------------------------- + + PlexusConfiguration[] mojoConfigurations = c.getChild("mojos").getChildren("mojo"); + + for (PlexusConfiguration component : mojoConfigurations) { + MojoDescriptor mojoDescriptor = buildComponentDescriptor(component, pluginDescriptor); + + pluginDescriptor.addMojo(mojoDescriptor); + } + + // ---------------------------------------------------------------------- + // Dependencies + // ---------------------------------------------------------------------- + + PlexusConfiguration[] dependencyConfigurations = + c.getChild("dependencies").getChildren("dependency"); + + List dependencies = new ArrayList<>(); + + for (PlexusConfiguration d : dependencyConfigurations) { + ComponentDependency cd = new ComponentDependency(); + + cd.setArtifactId(d.getChild("artifactId").getValue()); + + cd.setGroupId(d.getChild("groupId").getValue()); + + cd.setType(d.getChild("type").getValue()); + + cd.setVersion(d.getChild("version").getValue()); + + dependencies.add(cd); + } + + pluginDescriptor.setDependencies(dependencies); + + return pluginDescriptor; + } + + @SuppressWarnings("checkstyle:methodlength") + public MojoDescriptor buildComponentDescriptor(PlexusConfiguration c, PluginDescriptor pluginDescriptor) + throws PlexusConfigurationException { + MojoDescriptor mojo = new MojoDescriptor(); + mojo.setPluginDescriptor(pluginDescriptor); + + mojo.setGoal(c.getChild("goal").getValue()); + + mojo.setImplementation(c.getChild("implementation").getValue()); + + PlexusConfiguration langConfig = c.getChild("language"); + + if (langConfig != null) { + mojo.setLanguage(langConfig.getValue()); + } + + PlexusConfiguration configuratorConfig = c.getChild("configurator"); + + if (configuratorConfig != null) { + mojo.setComponentConfigurator(configuratorConfig.getValue()); + } + + PlexusConfiguration composerConfig = c.getChild("composer"); + + if (composerConfig != null) { + mojo.setComponentComposer(composerConfig.getValue()); + } + + String since = c.getChild("since").getValue(); + + if (since != null) { + mojo.setSince(since); + } + + PlexusConfiguration deprecated = c.getChild("deprecated", false); + + if (deprecated != null) { + mojo.setDeprecated(deprecated.getValue()); + } + + String phase = c.getChild("phase").getValue(); + + if (phase != null) { + mojo.setPhase(phase); + } + + String executePhase = c.getChild("executePhase").getValue(); + + if (executePhase != null) { + mojo.setExecutePhase(executePhase); + } + + String executeMojo = c.getChild("executeGoal").getValue(); + + if (executeMojo != null) { + mojo.setExecuteGoal(executeMojo); + } + + String executeLifecycle = c.getChild("executeLifecycle").getValue(); + + if (executeLifecycle != null) { + mojo.setExecuteLifecycle(executeLifecycle); + } + + mojo.setInstantiationStrategy(c.getChild("instantiationStrategy").getValue()); + + mojo.setDescription(c.getChild("description").getValue()); + + PlexusConfiguration dependencyResolution = c.getChild("requiresDependencyResolution", false); + + if (dependencyResolution != null) { + mojo.setDependencyResolutionRequired(dependencyResolution.getValue()); + } + + PlexusConfiguration dependencyCollection = c.getChild("requiresDependencyCollection", false); + + if (dependencyCollection != null) { + mojo.setDependencyCollectionRequired(dependencyCollection.getValue()); + } + + String directInvocationOnly = c.getChild("requiresDirectInvocation").getValue(); + + if (directInvocationOnly != null) { + mojo.setDirectInvocationOnly(Boolean.parseBoolean(directInvocationOnly)); + } + + String requiresProject = c.getChild("requiresProject").getValue(); + + if (requiresProject != null) { + mojo.setProjectRequired(Boolean.parseBoolean(requiresProject)); + } + + String requiresReports = c.getChild("requiresReports").getValue(); + + if (requiresReports != null) { + mojo.setRequiresReports(Boolean.parseBoolean(requiresReports)); + } + + String aggregator = c.getChild("aggregator").getValue(); + + if (aggregator != null) { + mojo.setAggregator(Boolean.parseBoolean(aggregator)); + } + + String requiresOnline = c.getChild("requiresOnline").getValue(); + + if (requiresOnline != null) { + mojo.setOnlineRequired(Boolean.parseBoolean(requiresOnline)); + } + + String inheritedByDefault = c.getChild("inheritedByDefault").getValue(); + + if (inheritedByDefault != null) { + mojo.setInheritedByDefault(Boolean.parseBoolean(inheritedByDefault)); + } + + String threadSafe = c.getChild("threadSafe").getValue(); + + if (threadSafe != null) { + mojo.setThreadSafe(Boolean.parseBoolean(threadSafe)); + } + + // ---------------------------------------------------------------------- + // Configuration + // ---------------------------------------------------------------------- + + PlexusConfiguration mojoConfig = c.getChild("configuration"); + mojo.setMojoConfiguration(mojoConfig); + + // ---------------------------------------------------------------------- + // Parameters + // ---------------------------------------------------------------------- + + PlexusConfiguration[] parameterConfigurations = c.getChild("parameters").getChildren("parameter"); + + List parameters = new ArrayList<>(); + + for (PlexusConfiguration d : parameterConfigurations) { + Parameter parameter = new Parameter(); + + parameter.setName(d.getChild("name").getValue()); + + parameter.setAlias(d.getChild("alias").getValue()); + + parameter.setType(d.getChild("type").getValue()); + + String required = d.getChild("required").getValue(); + + parameter.setRequired(Boolean.parseBoolean(required)); + + PlexusConfiguration editableConfig = d.getChild("editable"); + + // we need the null check for pre-build legacy plugins... + if (editableConfig != null) { + String editable = d.getChild("editable").getValue(); + + parameter.setEditable(editable == null || Boolean.parseBoolean(editable)); + } + + parameter.setDescription(d.getChild("description").getValue()); + + parameter.setDeprecated(d.getChild("deprecated").getValue()); + + parameter.setImplementation(d.getChild("implementation").getValue()); + + parameter.setSince(d.getChild("since").getValue()); + + PlexusConfiguration paramConfig = mojoConfig.getChild(parameter.getName(), false); + if (paramConfig != null) { + parameter.setExpression(paramConfig.getValue(null)); + parameter.setDefaultValue(paramConfig.getAttribute("default-value")); + } + + parameters.add(parameter); + } + + mojo.setParameters(parameters); + + // TODO this should not need to be handed off... + + // ---------------------------------------------------------------------- + // Requirements + // ---------------------------------------------------------------------- + + PlexusConfiguration[] requirements = c.getChild("requirements").getChildren("requirement"); + + for (PlexusConfiguration requirement : requirements) { + ComponentRequirement cr = new ComponentRequirement(); + + cr.setRole(requirement.getChild("role").getValue()); + + cr.setRoleHint(requirement.getChild("role-hint").getValue()); + + cr.setFieldName(requirement.getChild("field-name").getValue()); + + mojo.addRequirement(cr); + } + + return mojo; + } + + // ---------------------------------------------------------------------- + // + // ---------------------------------------------------------------------- + + public PlexusConfiguration buildConfiguration(Reader configuration) throws PlexusConfigurationException { + try { + return new XmlPlexusConfiguration(Xpp3DomBuilder.build(configuration)); + } catch (IOException | XmlPullParserException e) { + throw new PlexusConfigurationException(e.getMessage(), e); + } + } +} diff --git a/maven-plugin-tools-annotations/pom.xml b/maven-plugin-tools-annotations/pom.xml index 732fdbe67..bff4e9268 100644 --- a/maven-plugin-tools-annotations/pom.xml +++ b/maven-plugin-tools-annotations/pom.xml @@ -36,10 +36,6 @@ org.apache.maven maven-plugin-api - - org.apache.maven - maven-core - org.apache.maven maven-model diff --git a/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/JavaAnnotationsMojoDescriptorExtractor.java b/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/JavaAnnotationsMojoDescriptorExtractor.java index 8ba19ca93..25de3708c 100644 --- a/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/JavaAnnotationsMojoDescriptorExtractor.java +++ b/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/JavaAnnotationsMojoDescriptorExtractor.java @@ -60,6 +60,7 @@ import org.apache.maven.project.MavenProject; import org.apache.maven.tools.plugin.ExtendedMojoDescriptor; import org.apache.maven.tools.plugin.PluginToolsRequest; +import org.apache.maven.tools.plugin.Resolution; import org.apache.maven.tools.plugin.extractor.ExtractionException; import org.apache.maven.tools.plugin.extractor.GroupKey; import org.apache.maven.tools.plugin.extractor.MojoDescriptorExtractor; @@ -71,6 +72,7 @@ import org.apache.maven.tools.plugin.extractor.annotations.datamodel.ExecuteAnnotationContent; import org.apache.maven.tools.plugin.extractor.annotations.datamodel.MojoAnnotationContent; import org.apache.maven.tools.plugin.extractor.annotations.datamodel.ParameterAnnotationContent; +import org.apache.maven.tools.plugin.extractor.annotations.datamodel.ResolutionAnnotationContent; import org.apache.maven.tools.plugin.extractor.annotations.scanner.MojoAnnotatedClass; import org.apache.maven.tools.plugin.extractor.annotations.scanner.MojoAnnotationsScanner; import org.apache.maven.tools.plugin.extractor.annotations.scanner.MojoAnnotationsScannerRequest; @@ -791,6 +793,18 @@ private List toMojoDescriptors( mojoDescriptor.addParameter(parameter); } + // Dependencies annotations + Map resolutions = + getResolutionsParentHierarchy(mojoAnnotatedClass, mojoAnnotatedClasses); + + for (ResolutionAnnotationContent resolutionAnnotationContent : new TreeSet<>(resolutions.values())) { + Resolution resolution = new Resolution(); + resolution.setField(resolutionAnnotationContent.getFieldName()); + resolution.setPathScope(resolutionAnnotationContent.getPathScope()); + resolution.setRequestType(resolutionAnnotationContent.getRequestType()); + mojoDescriptor.addResolution(resolution); + } + mojoDescriptor.setPluginDescriptor(pluginDescriptor); mojoDescriptors.add(mojoDescriptor); @@ -847,6 +861,39 @@ protected List getParametersParent( return parameterAnnotationContents; } + protected Map getResolutionsParentHierarchy( + MojoAnnotatedClass mojoAnnotatedClass, Map mojoAnnotatedClasses) { + List resolutionAnnotationContents = new ArrayList<>(); + + resolutionAnnotationContents = + getResolutionsParent(mojoAnnotatedClass, resolutionAnnotationContents, mojoAnnotatedClasses); + + // move to parent first to build the Map + Collections.reverse(resolutionAnnotationContents); + + Map map = new HashMap<>(resolutionAnnotationContents.size()); + + for (ResolutionAnnotationContent resolutionAnnotationContent : resolutionAnnotationContents) { + map.put(resolutionAnnotationContent.getFieldName(), resolutionAnnotationContent); + } + return map; + } + + protected List getResolutionsParent( + MojoAnnotatedClass mojoAnnotatedClass, + List resolutionAnnotationContents, + Map mojoAnnotatedClasses) { + resolutionAnnotationContents.addAll(mojoAnnotatedClass.getResolutions().values()); + String parentClassName = mojoAnnotatedClass.getParentClassName(); + if (parentClassName != null) { + MojoAnnotatedClass parent = mojoAnnotatedClasses.get(parentClassName); + if (parent != null) { + return getResolutionsParent(parent, resolutionAnnotationContents, mojoAnnotatedClasses); + } + } + return resolutionAnnotationContents; + } + protected Map getComponentsParentHierarchy( MojoAnnotatedClass mojoAnnotatedClass, Map mojoAnnotatedClasses) { List componentAnnotationContents = new ArrayList<>(); diff --git a/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/datamodel/ExecuteAnnotationContent.java b/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/datamodel/ExecuteAnnotationContent.java index c1e3c9302..a8e7af4e5 100644 --- a/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/datamodel/ExecuteAnnotationContent.java +++ b/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/datamodel/ExecuteAnnotationContent.java @@ -19,6 +19,7 @@ package org.apache.maven.tools.plugin.extractor.annotations.datamodel; import java.lang.annotation.Annotation; +import java.util.Objects; import org.apache.maven.plugins.annotations.Execute; import org.apache.maven.plugins.annotations.LifecyclePhase; @@ -57,6 +58,20 @@ public String lifecycle() { } public void phase(String phase) { + if (phase != null && !phase.isEmpty()) { + for (LifecyclePhase p : LifecyclePhase.values()) { + if (Objects.equals(phase, p.id()) || Objects.equals(phase, p.name())) { + this.phase = p; + this.customPhase = null; + return; + } + } + this.phase = null; + this.customPhase = phase; + } else { + this.phase = null; + this.customPhase = null; + } this.phase = LifecyclePhase.valueOf(phase); } diff --git a/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/datamodel/MojoAnnotationContent.java b/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/datamodel/MojoAnnotationContent.java index a3b6f6e80..121969905 100644 --- a/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/datamodel/MojoAnnotationContent.java +++ b/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/datamodel/MojoAnnotationContent.java @@ -19,6 +19,7 @@ package org.apache.maven.tools.plugin.extractor.annotations.datamodel; import java.lang.annotation.Annotation; +import java.util.Objects; import org.apache.maven.plugins.annotations.InstantiationStrategy; import org.apache.maven.plugins.annotations.LifecyclePhase; @@ -69,7 +70,17 @@ public LifecyclePhase defaultPhase() { } public void defaultPhase(String phase) { - this.defaultPhase = LifecyclePhase.valueOf(phase); + if (phase != null && !phase.isEmpty()) { + for (LifecyclePhase p : LifecyclePhase.values()) { + if (Objects.equals(phase, p.id()) || Objects.equals(phase, p.name())) { + this.defaultPhase = p; + return; + } + } + throw new IllegalArgumentException("Could not find a matching phase for " + phase); + } else { + this.defaultPhase = null; + } } @Override @@ -81,6 +92,10 @@ public void requiresDependencyResolution(String requiresDependencyResolution) { this.requiresDependencyResolution = ResolutionScope.valueOf(requiresDependencyResolution); } + public void dependencyResolutionRequired(String dependencyResolutionRequired) { + this.requiresDependencyResolution = ResolutionScope.valueOf(dependencyResolutionRequired); + } + @Override public ResolutionScope requiresDependencyCollection() { return requiresDependencyCollection; @@ -117,6 +132,10 @@ public void requiresProject(boolean requiresProject) { this.requiresProject = requiresProject; } + public void projectRequired(boolean requiresProject) { + this.requiresProject = requiresProject; + } + @Override public boolean requiresReports() { return requiresReports; diff --git a/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/datamodel/ResolutionAnnotationContent.java b/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/datamodel/ResolutionAnnotationContent.java new file mode 100644 index 000000000..12ee4cbcd --- /dev/null +++ b/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/datamodel/ResolutionAnnotationContent.java @@ -0,0 +1,69 @@ +/* + * 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.tools.plugin.extractor.annotations.datamodel; + +import java.lang.annotation.Annotation; + +/** + * @author Guillaume Nodet + * @since 4.0 + */ +public class ResolutionAnnotationContent extends AnnotatedField { + private String pathScope; + + private String requestType; + + public ResolutionAnnotationContent(String fieldName) { + super(fieldName); + } + + public ResolutionAnnotationContent(String fieldName, String pathScope, String requestType) { + this(fieldName); + this.pathScope = pathScope; + this.requestType = requestType; + } + + public String getPathScope() { + return pathScope; + } + + public void setPathScope(String pathScope) { + this.pathScope = pathScope; + } + + public String getRequestType() { + return requestType; + } + + public void setRequestType(String requestType) { + this.requestType = requestType; + } + + public Class annotationType() { + return null; + } + + @Override + public String toString() { + return super.toString() + "ResolutionAnnotationContent" + + "{pathScope='" + + pathScope + '\'' + ", requestType='" + + requestType + '\'' + '}'; + } +} diff --git a/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/scanner/DefaultMojoAnnotationsScanner.java b/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/scanner/DefaultMojoAnnotationsScanner.java index a91aea24e..039dfe87d 100644 --- a/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/scanner/DefaultMojoAnnotationsScanner.java +++ b/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/scanner/DefaultMojoAnnotationsScanner.java @@ -27,10 +27,12 @@ import java.io.IOException; import java.io.InputStream; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.regex.Pattern; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; @@ -45,6 +47,7 @@ import org.apache.maven.tools.plugin.extractor.annotations.datamodel.ExecuteAnnotationContent; import org.apache.maven.tools.plugin.extractor.annotations.datamodel.MojoAnnotationContent; import org.apache.maven.tools.plugin.extractor.annotations.datamodel.ParameterAnnotationContent; +import org.apache.maven.tools.plugin.extractor.annotations.datamodel.ResolutionAnnotationContent; import org.apache.maven.tools.plugin.extractor.annotations.scanner.visitors.MojoAnnotationVisitor; import org.apache.maven.tools.plugin.extractor.annotations.scanner.visitors.MojoClassVisitor; import org.apache.maven.tools.plugin.extractor.annotations.scanner.visitors.MojoFieldVisitor; @@ -70,7 +73,7 @@ public class DefaultMojoAnnotationsScanner extends AbstractLogEnabled implements public static final String MOJO_V4 = MVN4_API + "Mojo"; public static final String EXECUTE_V4 = MVN4_API + "Execute"; public static final String PARAMETER_V4 = MVN4_API + "Parameter"; - public static final String COMPONENT_V4 = MVN4_API + "Component"; + public static final String RESOLUTION_V4 = MVN4_API + "Resolution"; public static final String MOJO_V3 = Mojo.class.getName(); public static final String EXECUTE_V3 = Execute.class.getName(); @@ -88,15 +91,23 @@ public Map scan(MojoAnnotationsScannerRequest reques Map mojoAnnotatedClasses = new HashMap<>(); try { + String mavenApiVersion = null; for (Artifact dependency : request.getDependencies()) { scan(mojoAnnotatedClasses, dependency.getFile(), request.getIncludePatterns(), dependency, true); if (request.getMavenApiVersion() == null && dependency.getGroupId().equals("org.apache.maven") && (dependency.getArtifactId().equals("maven-plugin-api") || dependency.getArtifactId().equals("maven-api-core"))) { - request.setMavenApiVersion(dependency.getVersion()); + String version = dependency.getVersion(); + if (mavenApiVersion != null && !Objects.equals(version, mavenApiVersion)) { + throw new UnsupportedOperationException("Mixing Maven 3 and Maven 4 plugins is not supported." + + " Fix your dependencies so that you depend either on maven-plugin-api for a Maven 3 plugin," + + " or maven-api-core for a Maven 4 plugin."); + } + mavenApiVersion = version; } } + request.setMavenApiVersion(mavenApiVersion); for (File classDirectory : request.getClassesDirectories()) { scan( @@ -331,17 +342,15 @@ protected void analyzeVisitors(MojoClassVisitor mojoClassVisitor) throws Extract } // @Component annotations - List mojoFieldVisitors = - mojoClassVisitor.findFieldWithAnnotation(new HashSet<>(Arrays.asList(COMPONENT_V3, COMPONENT_V4))); - for (MojoFieldVisitor mojoFieldVisitor : mojoFieldVisitors) { + List mojoComponentVisitors = + mojoClassVisitor.findFieldWithAnnotation(new HashSet<>(Arrays.asList(COMPONENT_V3))); + for (MojoFieldVisitor mojoComponentVisitor : mojoComponentVisitors) { ComponentAnnotationContent componentAnnotationContent = - new ComponentAnnotationContent(mojoFieldVisitor.getFieldName()); + new ComponentAnnotationContent(mojoComponentVisitor.getFieldName()); - Map annotationVisitorMap = mojoFieldVisitor.getAnnotationVisitorMap(); + Map annotationVisitorMap = + mojoComponentVisitor.getAnnotationVisitorMap(); MojoAnnotationVisitor annotationVisitor = annotationVisitorMap.get(COMPONENT_V3); - if (annotationVisitor == null) { - annotationVisitor = annotationVisitorMap.get(COMPONENT_V4); - } if (annotationVisitor != null) { for (Map.Entry entry : @@ -357,13 +366,44 @@ protected void analyzeVisitors(MojoClassVisitor mojoClassVisitor) throws Extract } if (StringUtils.isEmpty(componentAnnotationContent.getRoleClassName())) { - componentAnnotationContent.setRoleClassName(mojoFieldVisitor.getClassName()); + componentAnnotationContent.setRoleClassName(mojoComponentVisitor.getClassName()); } } mojoAnnotatedClass .getComponents() .put(componentAnnotationContent.getFieldName(), componentAnnotationContent); } + + // @Resolution annotations + List mojoResolutionVisitors = + mojoClassVisitor.findFieldWithAnnotation(Collections.singleton(RESOLUTION_V4)); + for (MojoFieldVisitor mojoResolutionVisitor : mojoResolutionVisitors) { + ResolutionAnnotationContent dependenciesAnnotationContent = + new ResolutionAnnotationContent(mojoResolutionVisitor.getFieldName()); + + Map annotationVisitorMap = + mojoResolutionVisitor.getAnnotationVisitorMap(); + MojoAnnotationVisitor annotationVisitor = annotationVisitorMap.get(RESOLUTION_V4); + + if (annotationVisitor != null) { + for (Map.Entry entry : + annotationVisitor.getAnnotationValues().entrySet()) { + String methodName = entry.getKey(); + if ("pathScope".equals(methodName)) { + dependenciesAnnotationContent.setPathScope((String) entry.getValue()); + } else if ("requestType".equals(methodName)) { + dependenciesAnnotationContent.setRequestType((String) entry.getValue()); + } else { + throw new IllegalStateException("Unsupported method: " + methodName); + } + } + } + + mojoAnnotatedClass + .getResolutions() + .put(dependenciesAnnotationContent.getFieldName(), dependenciesAnnotationContent); + } + } catch (ReflectorException e) { throw new ExtractionException(e.getMessage(), e); } diff --git a/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/scanner/MojoAnnotatedClass.java b/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/scanner/MojoAnnotatedClass.java index f408d8dcf..12faac55f 100644 --- a/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/scanner/MojoAnnotatedClass.java +++ b/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/scanner/MojoAnnotatedClass.java @@ -26,6 +26,7 @@ import org.apache.maven.tools.plugin.extractor.annotations.datamodel.ExecuteAnnotationContent; import org.apache.maven.tools.plugin.extractor.annotations.datamodel.MojoAnnotationContent; import org.apache.maven.tools.plugin.extractor.annotations.datamodel.ParameterAnnotationContent; +import org.apache.maven.tools.plugin.extractor.annotations.datamodel.ResolutionAnnotationContent; /** * @author Olivier Lamy @@ -52,6 +53,11 @@ public class MojoAnnotatedClass { */ private Map components; + /** + * key is field name + */ + private Map resolutions; + /** * artifact which contains this annotation */ @@ -123,6 +129,18 @@ public MojoAnnotatedClass setComponents(Map return this; } + public Map getResolutions() { + if (this.resolutions == null) { + this.resolutions = new HashMap<>(); + } + return resolutions; + } + + public MojoAnnotatedClass setResolutions(Map resolutions) { + this.resolutions = resolutions; + return this; + } + public String getParentClassName() { return parentClassName; } @@ -163,6 +181,7 @@ public String toString() { sb.append(", execute=").append(execute); sb.append(", parameters=").append(parameters); sb.append(", components=").append(components); + sb.append(", dependencies=").append(resolutions); sb.append(", v4api=").append(v4Api); sb.append('}'); return sb.toString(); diff --git a/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/scanner/MojoAnnotationsScanner.java b/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/scanner/MojoAnnotationsScanner.java index 890f85128..3622b261f 100644 --- a/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/scanner/MojoAnnotationsScanner.java +++ b/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/scanner/MojoAnnotationsScanner.java @@ -51,7 +51,8 @@ public interface MojoAnnotationsScanner { Component.class.getName(), Deprecated.class.getName(), V4_API_ANNOTATIONS_PACKAGE + ".Parameter", - V4_API_ANNOTATIONS_PACKAGE + ".Component"); + V4_API_ANNOTATIONS_PACKAGE + ".Component", + V4_API_ANNOTATIONS_PACKAGE + ".Resolution"); List METHOD_LEVEL_ANNOTATIONS = Arrays.asList( Parameter.class.getName(), Deprecated.class.getName(), V4_API_ANNOTATIONS_PACKAGE + ".Parameter"); diff --git a/maven-plugin-tools-annotations/src/test/java/org/apache/maven/tools/plugin/extractor/annotations/ParametersWithGenericsMojo.java b/maven-plugin-tools-annotations/src/test/java/org/apache/maven/tools/plugin/extractor/annotations/ParametersWithGenericsMojo.java index d5796ba5b..5de14478e 100644 --- a/maven-plugin-tools-annotations/src/test/java/org/apache/maven/tools/plugin/extractor/annotations/ParametersWithGenericsMojo.java +++ b/maven-plugin-tools-annotations/src/test/java/org/apache/maven/tools/plugin/extractor/annotations/ParametersWithGenericsMojo.java @@ -46,6 +46,9 @@ public class ParametersWithGenericsMojo extends AbstractMojo { @Parameter private Collection integerArrayCollection; + @Parameter + private Map> stringListStringMap; + @Override public void execute() throws MojoExecutionException, MojoFailureException {} diff --git a/maven-plugin-tools-annotations/src/test/java/org/apache/maven/tools/plugin/extractor/annotations/scanner/DefaultMojoAnnotationsScannerTest.java b/maven-plugin-tools-annotations/src/test/java/org/apache/maven/tools/plugin/extractor/annotations/scanner/DefaultMojoAnnotationsScannerTest.java index 83dd04c47..bc8c0723b 100644 --- a/maven-plugin-tools-annotations/src/test/java/org/apache/maven/tools/plugin/extractor/annotations/scanner/DefaultMojoAnnotationsScannerTest.java +++ b/maven-plugin-tools-annotations/src/test/java/org/apache/maven/tools/plugin/extractor/annotations/scanner/DefaultMojoAnnotationsScannerTest.java @@ -132,6 +132,12 @@ void scanParametersWithGenerics() throws ExtractionException, IOException { assertNotNull(parameter); assertEquals("java.util.List", parameter.getClassName()); assertThat(parameter.getTypeParameters()).containsExactly("java.lang.Number"); + + parameter = annotatedClass.getParameters().get("stringListStringMap"); + assertNotNull(parameter); + assertEquals("java.util.Map", parameter.getClassName()); + assertThat(parameter.getTypeParameters()) + .containsExactly("java.lang.String", "java.util.List"); } @Test diff --git a/maven-plugin-tools-api/src/main/java/org/apache/maven/tools/plugin/ExtendedMojoDescriptor.java b/maven-plugin-tools-api/src/main/java/org/apache/maven/tools/plugin/ExtendedMojoDescriptor.java index cf227272c..4cf50db1a 100644 --- a/maven-plugin-tools-api/src/main/java/org/apache/maven/tools/plugin/ExtendedMojoDescriptor.java +++ b/maven-plugin-tools-api/src/main/java/org/apache/maven/tools/plugin/ExtendedMojoDescriptor.java @@ -18,6 +18,8 @@ */ package org.apache.maven.tools.plugin; +import java.util.ArrayList; +import java.util.List; import java.util.Objects; import org.apache.maven.plugin.descriptor.MojoDescriptor; @@ -31,6 +33,7 @@ public class ExtendedMojoDescriptor extends MojoDescriptor { private final boolean containsXhtmlTextValues; private boolean v4Api; + private List resolutions; public ExtendedMojoDescriptor() { this(false); @@ -63,12 +66,24 @@ public void setV4Api(boolean v4Api) { this.v4Api = v4Api; } + public List getResolutions() { + return resolutions; + } + + public void setResolutions(List resolutions) { + this.resolutions = resolutions; + } + + public void addResolution(Resolution resolution) { + if (this.resolutions == null) { + this.resolutions = new ArrayList<>(); + } + this.resolutions.add(resolution); + } + @Override public int hashCode() { - final int prime = 31; - int result = super.hashCode(); - result = prime * result + Objects.hash(containsXhtmlTextValues); - return result; + return Objects.hash(containsXhtmlTextValues, v4Api, resolutions); } @Override @@ -83,6 +98,8 @@ public boolean equals(Object obj) { return false; } ExtendedMojoDescriptor other = (ExtendedMojoDescriptor) obj; - return containsXhtmlTextValues == other.containsXhtmlTextValues; + return Objects.equals(containsXhtmlTextValues, other.containsXhtmlTextValues) + && Objects.equals(v4Api, other.v4Api) + && Objects.equals(resolutions, other.resolutions); } } diff --git a/maven-plugin-tools-api/src/main/java/org/apache/maven/tools/plugin/ExtendedPluginDescriptor.java b/maven-plugin-tools-api/src/main/java/org/apache/maven/tools/plugin/ExtendedPluginDescriptor.java index bb3dc5c04..0ae9e9352 100644 --- a/maven-plugin-tools-api/src/main/java/org/apache/maven/tools/plugin/ExtendedPluginDescriptor.java +++ b/maven-plugin-tools-api/src/main/java/org/apache/maven/tools/plugin/ExtendedPluginDescriptor.java @@ -18,7 +18,6 @@ */ package org.apache.maven.tools.plugin; -import java.io.IOException; import java.util.List; import java.util.Map; import java.util.Objects; @@ -29,9 +28,7 @@ import org.apache.maven.plugin.descriptor.DuplicateMojoDescriptorException; import org.apache.maven.plugin.descriptor.MojoDescriptor; import org.apache.maven.plugin.descriptor.PluginDescriptor; -import org.apache.maven.plugin.lifecycle.Lifecycle; import org.codehaus.plexus.classworlds.realm.ClassRealm; -import org.codehaus.plexus.util.xml.pull.XmlPullParserException; /** * Extensions to {@link PluginDescriptor} not supported by Maven 3.2.5. @@ -91,6 +88,12 @@ public void addMojo(MojoDescriptor mojoDescriptor) throws DuplicateMojoDescripto delegate.addMojo(mojoDescriptor); } + public void addMojos(List mojos) throws DuplicateMojoDescriptorException { + for (MojoDescriptor mojoDescriptor : mojos) { + addMojo(mojoDescriptor); + } + } + public String getGroupId() { return delegate.getGroupId(); } @@ -222,11 +225,6 @@ public void setPluginArtifact(Artifact pluginArtifact) { delegate.setPluginArtifact(pluginArtifact); } - @Override - public Lifecycle getLifecycleMapping(String lifecycleId) throws IOException, XmlPullParserException { - return delegate.getLifecycleMapping(lifecycleId); - } - public PluginDescriptor clone() { return delegate.clone(); } diff --git a/maven-plugin-tools-api/src/main/java/org/apache/maven/tools/plugin/Resolution.java b/maven-plugin-tools-api/src/main/java/org/apache/maven/tools/plugin/Resolution.java new file mode 100644 index 000000000..02d945730 --- /dev/null +++ b/maven-plugin-tools-api/src/main/java/org/apache/maven/tools/plugin/Resolution.java @@ -0,0 +1,50 @@ +/* + * 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.tools.plugin; + +public class Resolution { + + String field; + String pathScope; + String requestType; + + public String getField() { + return field; + } + + public void setField(String field) { + this.field = field; + } + + public String getPathScope() { + return pathScope; + } + + public void setPathScope(String pathScope) { + this.pathScope = pathScope; + } + + public String getRequestType() { + return requestType; + } + + public void setRequestType(String requestType) { + this.requestType = requestType; + } +} diff --git a/maven-plugin-tools-generators/pom.xml b/maven-plugin-tools-generators/pom.xml index b2af7953b..dd1aabe94 100644 --- a/maven-plugin-tools-generators/pom.xml +++ b/maven-plugin-tools-generators/pom.xml @@ -54,6 +54,8 @@ org.apache.maven maven-plugin-api + ${maven3Version} + provided org.apache.maven @@ -89,6 +91,15 @@ ${slf4jVersion} + + org.ow2.asm + asm + + + org.ow2.asm + asm-commons + + org.jsoup @@ -108,6 +119,11 @@ junit-jupiter-engine test + + org.apache.maven.resolver + maven-resolver-impl + ${resolverVersion} + org.codehaus.plexus plexus-testing diff --git a/maven-plugin-tools-generators/src/main/java/org/apache/maven/tools/plugin/generator/PluginDescriptorFilesGenerator.java b/maven-plugin-tools-generators/src/main/java/org/apache/maven/tools/plugin/generator/PluginDescriptorFilesGenerator.java index c6923de67..59b2105cc 100644 --- a/maven-plugin-tools-generators/src/main/java/org/apache/maven/tools/plugin/generator/PluginDescriptorFilesGenerator.java +++ b/maven-plugin-tools-generators/src/main/java/org/apache/maven/tools/plugin/generator/PluginDescriptorFilesGenerator.java @@ -37,6 +37,7 @@ import org.apache.maven.tools.plugin.ExtendedMojoDescriptor; import org.apache.maven.tools.plugin.ExtendedPluginDescriptor; import org.apache.maven.tools.plugin.PluginToolsRequest; +import org.apache.maven.tools.plugin.Resolution; import org.apache.maven.tools.plugin.javadoc.JavadocLinkGenerator; import org.apache.maven.tools.plugin.util.PluginUtils; import org.codehaus.plexus.util.StringUtils; @@ -110,6 +111,9 @@ public void writeDescriptor(File destinationFile, PluginToolsRequest request, De destinationFile.getParentFile().mkdirs(); } + String apiVersion = request.getPluginDescriptor().getRequiredMavenVersion(); + boolean isV4 = apiVersion != null && apiVersion.startsWith("4."); + try (Writer writer = new OutputStreamWriter(new CachingOutputStream(destinationFile), UTF_8)) { XMLWriter w = new PrettyPrintXMLWriter(writer, UTF_8.name(), null); @@ -128,6 +132,13 @@ public void writeDescriptor(File destinationFile, PluginToolsRequest request, De w.writeMarkup("\n\n\n"); w.startElement("plugin"); + if (isV4) { + w.addAttribute("xmlns", "http://maven.apache.org/PLUGIN/2.0.0"); + w.addAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance"); + w.addAttribute( + "xsi:location", + "http://maven.apache.org/PLUGIN/2.0.0 https://maven.apache.org/xsd/plugin-2.0.0.xsd"); + } GeneratorUtils.element(w, "name", pluginDescriptor.getName()); @@ -178,13 +189,13 @@ public void writeDescriptor(File destinationFile, PluginToolsRequest request, De PluginUtils.sortMojos(descriptors); for (MojoDescriptor descriptor : descriptors) { - processMojoDescriptor(descriptor, w, type, javadocLinkGenerator); + processMojoDescriptor(descriptor, w, type, javadocLinkGenerator, isV4); } } w.endElement(); - if (type != DescriptorType.LIMITED_FOR_HELP_MOJO) { + if (!isV4 && type != DescriptorType.LIMITED_FOR_HELP_MOJO) { GeneratorUtils.writeDependencies(w, pluginDescriptor); } @@ -221,7 +232,8 @@ protected void processMojoDescriptor( MojoDescriptor mojoDescriptor, XMLWriter w, DescriptorType type, - JavadocLinkGenerator javadocLinkGenerator) { + JavadocLinkGenerator javadocLinkGenerator, + boolean isV4) { boolean containsXhtmlTextValues = mojoDescriptor instanceof ExtendedMojoDescriptor && ((ExtendedMojoDescriptor) mojoDescriptor).containsXhtmlTextValues(); @@ -251,27 +263,36 @@ protected void processMojoDescriptor( // // ---------------------------------------------------------------------- - if (StringUtils.isNotEmpty(mojoDescriptor.isDependencyResolutionRequired())) { - GeneratorUtils.element(w, "requiresDependencyResolution", mojoDescriptor.isDependencyResolutionRequired()); + if (StringUtils.isNotEmpty(mojoDescriptor.getDependencyResolutionRequired())) { + GeneratorUtils.element( + w, + isV4 ? "dependencyResolution" : "requiresDependencyResolution", + mojoDescriptor.getDependencyResolutionRequired()); } // ---------------------------------------------------------------------- // // ---------------------------------------------------------------------- - GeneratorUtils.element(w, "requiresDirectInvocation", String.valueOf(mojoDescriptor.isDirectInvocationOnly())); + GeneratorUtils.element( + w, + isV4 ? "directInvocationOnly" : "requiresDirectInvocation", + String.valueOf(mojoDescriptor.isDirectInvocationOnly())); // ---------------------------------------------------------------------- // // ---------------------------------------------------------------------- - GeneratorUtils.element(w, "requiresProject", String.valueOf(mojoDescriptor.isProjectRequired())); + GeneratorUtils.element( + w, isV4 ? "projectRequired" : "requiresProject", String.valueOf(mojoDescriptor.isProjectRequired())); // ---------------------------------------------------------------------- // // ---------------------------------------------------------------------- - GeneratorUtils.element(w, "requiresReports", String.valueOf(mojoDescriptor.isRequiresReports())); + if (!isV4) { + GeneratorUtils.element(w, "requiresReports", String.valueOf(mojoDescriptor.isRequiresReports())); + } // ---------------------------------------------------------------------- // @@ -283,7 +304,8 @@ protected void processMojoDescriptor( // // ---------------------------------------------------------------------- - GeneratorUtils.element(w, "requiresOnline", String.valueOf(mojoDescriptor.isOnlineRequired())); + GeneratorUtils.element( + w, isV4 ? "onlineRequired" : "requiresOnline", String.valueOf(mojoDescriptor.isOnlineRequired())); // ---------------------------------------------------------------------- // @@ -345,7 +367,7 @@ protected void processMojoDescriptor( // // ---------------------------------------------------------------------- - if (StringUtils.isNotEmpty(mojoDescriptor.getComponentComposer())) { + if (!isV4 && StringUtils.isNotEmpty(mojoDescriptor.getComponentComposer())) { w.startElement("composer"); w.writeText(mojoDescriptor.getComponentComposer()); w.endElement(); @@ -355,17 +377,22 @@ protected void processMojoDescriptor( // // ---------------------------------------------------------------------- - w.startElement("instantiationStrategy"); - w.writeText(mojoDescriptor.getInstantiationStrategy()); - w.endElement(); + if (!isV4) { + w.startElement("instantiationStrategy"); + w.writeText(mojoDescriptor.getInstantiationStrategy()); + w.endElement(); + } // ---------------------------------------------------------------------- // Strategy for handling repeated reference to mojo in // the calculated (decorated, resolved) execution stack // ---------------------------------------------------------------------- - w.startElement("executionStrategy"); - w.writeText(mojoDescriptor.getExecutionStrategy()); - w.endElement(); + + if (!isV4) { + w.startElement("executionStrategy"); + w.writeText(mojoDescriptor.getExecutionStrategy()); + w.endElement(); + } // ---------------------------------------------------------------------- // @@ -407,14 +434,12 @@ protected void processMojoDescriptor( ExtendedMojoDescriptor extendedMojoDescriptor = (ExtendedMojoDescriptor) mojoDescriptor; if (extendedMojoDescriptor.getDependencyCollectionRequired() != null) { GeneratorUtils.element( - w, "requiresDependencyCollection", extendedMojoDescriptor.getDependencyCollectionRequired()); + w, + isV4 ? "dependencyCollection" : "requiresDependencyCollection", + extendedMojoDescriptor.getDependencyCollectionRequired()); } - - GeneratorUtils.element(w, "threadSafe", String.valueOf(extendedMojoDescriptor.isThreadSafe())); - - boolean v4Api = extendedMojoDescriptor.isV4Api(); - if (v4Api) { - GeneratorUtils.element(w, "v4Api", String.valueOf(v4Api)); + if (!isV4) { + GeneratorUtils.element(w, "threadSafe", String.valueOf(extendedMojoDescriptor.isThreadSafe())); } } @@ -495,7 +520,7 @@ else if (type != DescriptorType.LIMITED_FOR_HELP_MOJO || parameter.isEditable()) } } - if (parameter.getImplementation() != null) { + if (!isV4 && parameter.getImplementation() != null) { GeneratorUtils.element(w, "implementation", parameter.getImplementation()); } @@ -506,9 +531,18 @@ else if (type != DescriptorType.LIMITED_FOR_HELP_MOJO || parameter.isEditable()) GeneratorUtils.element( w, "description", getTextValue(type, containsXhtmlTextValues, parameter.getDescription())); - if (StringUtils.isNotEmpty(parameter.getDefaultValue()) - || StringUtils.isNotEmpty(parameter.getExpression())) { - configuration.add(parameter); + if (isV4) { + if (StringUtils.isNotEmpty(parameter.getExpression())) { + GeneratorUtils.element(w, "expression", parameter.getExpression()); + } + if (StringUtils.isNotEmpty(parameter.getDefaultValue())) { + GeneratorUtils.element(w, "defaultValue", parameter.getDefaultValue()); + } + } else { + if (StringUtils.isNotEmpty(parameter.getDefaultValue()) + || StringUtils.isNotEmpty(parameter.getExpression())) { + configuration.add(parameter); + } } w.endElement(); @@ -580,6 +614,26 @@ else if (type != DescriptorType.LIMITED_FOR_HELP_MOJO || parameter.isEditable()) w.endElement(); } + // ---------------------------------------------------------------------- + // Dependencies + // ---------------------------------------------------------------------- + + if (mojoDescriptor instanceof ExtendedMojoDescriptor) { + ExtendedMojoDescriptor extendedMojoDescriptor = (ExtendedMojoDescriptor) mojoDescriptor; + List resolutions = extendedMojoDescriptor.getResolutions(); + if (resolutions != null && !resolutions.isEmpty()) { + w.startElement("resolutions"); + for (Resolution resolution : resolutions) { + w.startElement("resolution"); + GeneratorUtils.element(w, "field", resolution.getField()); + GeneratorUtils.element(w, "pathScope", resolution.getPathScope()); + GeneratorUtils.element(w, "requestType", resolution.getRequestType()); + w.endElement(); + } + w.endElement(); + } + } + w.endElement(); } diff --git a/maven-plugin-tools-generators/src/main/resources/help-class-source-v4.vm b/maven-plugin-tools-generators/src/main/resources/help-class-source-v4.vm index 0ac5b891a..008c52192 100644 --- a/maven-plugin-tools-generators/src/main/resources/help-class-source-v4.vm +++ b/maven-plugin-tools-generators/src/main/resources/help-class-source-v4.vm @@ -18,8 +18,8 @@ package ${helpPackageName}; #end +import org.apache.maven.api.di.Inject; import org.apache.maven.api.plugin.MojoException; -import org.apache.maven.api.plugin.annotations.Component; import org.apache.maven.api.plugin.annotations.Mojo; import org.apache.maven.api.plugin.annotations.Parameter; import org.apache.maven.api.plugin.Log; @@ -43,11 +43,11 @@ import java.util.List; * Call mvn ${goalPrefix}:help -Ddetail=true -Dgoal=<goal-name> to display parameter details. * @author maven-plugin-tools */ -@Mojo( name = "help", requiresProject = false ) +@Mojo( name = "help", projectRequired = false ) public class HelpMojo implements org.apache.maven.api.plugin.Mojo { - @Component + @Inject private Log logger; /** @@ -189,6 +189,21 @@ public class HelpMojo return getSingleChild( node, elementName ).getTextContent(); } + private static String getValueOr( Node node, String elementName, String def ) + throws MojoException + { + List namedChild = findNamedChild( node, elementName ); + if ( namedChild.isEmpty() ) + { + return def; + } + if ( namedChild.size() > 1 ) + { + throw new MojoException( "Multiple " + elementName + " in plugin-help.xml" ); + } + return namedChild.get( 0 ).getTextContent(); + } + private static Node getSingleChild( Node node, String elementName ) throws MojoException { @@ -286,10 +301,10 @@ public class HelpMojo fieldConfigurationElement = (Element) findSingleChild( configurationElement, parameterName ); } - String parameterDefaultValue = ""; - if ( fieldConfigurationElement != null && fieldConfigurationElement.hasAttribute( "default-value" ) ) + String parameterDefaultValue = getValueOr( parameter, "defaultValue", "" ); + if ( isNotEmpty( parameterDefaultValue ) ) { - parameterDefaultValue = " (Default: " + fieldConfigurationElement.getAttribute( "default-value" ) + ")"; + parameterDefaultValue = " (Default: " + parameterDefaultValue + ")"; } append( sb, parameterName + parameterDefaultValue, 2 ); Node deprecated = findSingleChild( parameter, "deprecated" ); @@ -305,9 +320,11 @@ public class HelpMojo { append( sb, "Required: Yes", 3 ); } - if ( ( fieldConfigurationElement != null ) && isNotEmpty( fieldConfigurationElement.getTextContent() ) ) + + String parameterExpression = getValueOr( parameter, "expression", "" ); + if ( isNotEmpty( parameterExpression ) ) { - String property = getPropertyFromExpression( fieldConfigurationElement.getTextContent() ); + String property = getPropertyFromExpression( parameterExpression ); append( sb, "User property: " + property, 3 ); } diff --git a/maven-plugin-tools-generators/src/test/java/org/apache/maven/tools/plugin/generator/AbstractGeneratorTestCase.java b/maven-plugin-tools-generators/src/test/java/org/apache/maven/tools/plugin/generator/AbstractGeneratorTestCase.java index f592b6319..4b63712f7 100644 --- a/maven-plugin-tools-generators/src/test/java/org/apache/maven/tools/plugin/generator/AbstractGeneratorTestCase.java +++ b/maven-plugin-tools-generators/src/test/java/org/apache/maven/tools/plugin/generator/AbstractGeneratorTestCase.java @@ -36,6 +36,7 @@ import org.apache.maven.tools.plugin.DefaultPluginToolsRequest; import org.codehaus.plexus.component.repository.ComponentDependency; import org.codehaus.plexus.util.FileUtils; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; /** @@ -105,7 +106,74 @@ public void testGenerator() throws Exception { extendPluginDescriptor(pluginDescriptor); generator.execute(destinationDirectory, new DefaultPluginToolsRequest(mavenProject, pluginDescriptor)); - validate(destinationDirectory); + validate(destinationDirectory, false); + + FileUtils.deleteDirectory(destinationDirectory); + } + + @Test + @Disabled + public void testGeneratorV4() throws Exception { + setupGenerator(); + + MojoDescriptor mojoDescriptor = new MojoDescriptor(); + mojoDescriptor.setGoal("testGoal"); + mojoDescriptor.setImplementation("org.apache.maven.tools.plugin.generator.TestMojo"); + mojoDescriptor.setDependencyResolutionRequired("compile"); + mojoDescriptor.setSince("mojoSince"); + + List params = new ArrayList<>(); + + Parameter param = new Parameter(); + param.setExpression("${project.build.directory}"); + param.setDefaultValue(""); + param.setName("dir"); + param.setRequired(true); + param.setType("java.lang.String"); + param.setDescription("Test parameter description"); + param.setAlias("some.alias"); + param.setSince("paramDirSince"); + params.add(param); + + param = new Parameter(); + param.setName("withoutSince"); + param.setType("java.lang.String"); + params.add(param); + + mojoDescriptor.setParameters(params); + + PluginDescriptor pluginDescriptor = new PluginDescriptor(); + mojoDescriptor.setPluginDescriptor(pluginDescriptor); + + pluginDescriptor.addMojo(mojoDescriptor); + + pluginDescriptor.setArtifactId("maven-unitTesting-plugin"); + pluginDescriptor.setGoalPrefix("test"); + + ComponentDependency dependency = new ComponentDependency(); + dependency.setGroupId("testGroup"); + dependency.setArtifactId("testArtifact"); + dependency.setVersion("0.0.0"); + + pluginDescriptor.setDependencies(Collections.singletonList(dependency)); + + File destinationDirectory = + Files.createTempDirectory("testGenerator-outDir").toFile(); + destinationDirectory.mkdir(); + + MavenProject mavenProject = new MavenProject(); + mavenProject.setGroupId("foo"); + mavenProject.setArtifactId("bar"); + Build build = new Build(); + build.setDirectory(basedir + "/target"); + build.setOutputDirectory(basedir + "/target"); + mavenProject.setBuild(build); + extendPluginDescriptor(pluginDescriptor); + DefaultPluginToolsRequest request = new DefaultPluginToolsRequest(mavenProject, pluginDescriptor); + pluginDescriptor.setRequiredMavenVersion("4.0.0"); + generator.execute(destinationDirectory, request); + + validate(destinationDirectory, true); FileUtils.deleteDirectory(destinationDirectory); } @@ -145,7 +213,7 @@ protected void setupGenerator() throws Exception { // // ---------------------------------------------------------------------- - protected void validate(File destinationDirectory) throws Exception { + protected void validate(File destinationDirectory, boolean isV4) throws Exception { // empty } } diff --git a/maven-plugin-tools-generators/src/test/java/org/apache/maven/tools/plugin/generator/PluginDescriptorFilesGeneratorTest.java b/maven-plugin-tools-generators/src/test/java/org/apache/maven/tools/plugin/generator/PluginDescriptorFilesGeneratorTest.java index eb35539e4..98fd2e41e 100644 --- a/maven-plugin-tools-generators/src/test/java/org/apache/maven/tools/plugin/generator/PluginDescriptorFilesGeneratorTest.java +++ b/maven-plugin-tools-generators/src/test/java/org/apache/maven/tools/plugin/generator/PluginDescriptorFilesGeneratorTest.java @@ -60,35 +60,33 @@ protected void extendPluginDescriptor(PluginDescriptor pluginDescriptor) throws } @Override - protected void validate(File destinationDirectory) throws Exception { + protected void validate(File destinationDirectory, boolean isV4) throws Exception { PluginDescriptorBuilder pdb = new PluginDescriptorBuilder(); File pluginDescriptorFile = new File(destinationDirectory, "plugin.xml"); String pd = readFile(pluginDescriptorFile); + System.err.println(pd); + PluginDescriptor pluginDescriptor = pdb.build(new StringReader(pd)); assertEquals(1, pluginDescriptor.getMojos().size()); MojoDescriptor mojoDescriptor = pluginDescriptor.getMojos().get(0); - checkMojo(mojoDescriptor); + checkMojo(mojoDescriptor, isV4); // ---------------------------------------------------------------------- // Dependencies // ---------------------------------------------------------------------- - List dependencies = pluginDescriptor.getDependencies(); - - checkDependency("testGroup", "testArtifact", "0.0.0", dependencies.get(0)); + if (!isV4) { + List dependencies = pluginDescriptor.getDependencies(); - assertEquals(1, dependencies.size()); - - ComponentDependency dependency = dependencies.get(0); - assertEquals("testGroup", dependency.getGroupId()); - assertEquals("testArtifact", dependency.getArtifactId()); - assertEquals("0.0.0", dependency.getVersion()); + assertEquals(1, dependencies.size()); + checkDependency("testGroup", "testArtifact", "0.0.0", dependencies.get(0)); + } } private String readFile(File pluginDescriptorFile) throws IOException { @@ -105,15 +103,19 @@ private String readFile(File pluginDescriptorFile) throws IOException { return sWriter.toString(); } - private void checkMojo(MojoDescriptor mojoDescriptor) { + private void checkMojo(MojoDescriptor mojoDescriptor, boolean isV4) { assertEquals("test:testGoal", mojoDescriptor.getFullGoalName()); assertEquals("org.apache.maven.tools.plugin.generator.TestMojo", mojoDescriptor.getImplementation()); // The following should be defaults - assertEquals("per-lookup", mojoDescriptor.getInstantiationStrategy()); + if (!isV4) { + assertEquals("per-lookup", mojoDescriptor.getInstantiationStrategy()); + } - assertNotNull(mojoDescriptor.isDependencyResolutionRequired()); + if (!isV4) { + assertNotNull(mojoDescriptor.getDependencyResolutionRequired()); + } // check the default parameter checkParameter(mojoDescriptor.getParameters().get(0)); @@ -124,12 +126,17 @@ private void checkMojo(MojoDescriptor mojoDescriptor) { assertEquals("parameterWithGenerics", parameterWithGenerics.getName()); assertEquals("java.util.Collection", parameterWithGenerics.getType()); - PlexusConfiguration configurations = mojoDescriptor.getMojoConfiguration(); - assertNotNull(configurations); - PlexusConfiguration configuration = configurations.getChild("parameterWithGenerics"); - assertEquals("java.util.Collection", configuration.getAttribute("implementation")); - assertEquals("a,b,c", configuration.getAttribute("default-value")); - assertEquals("${customParam}", configuration.getValue()); + if (isV4) { + assertEquals("${customParam}", parameterWithGenerics.getExpression()); + assertEquals("a,b,c", parameterWithGenerics.getDefaultValue()); + } else { + PlexusConfiguration configurations = mojoDescriptor.getMojoConfiguration(); + assertNotNull(configurations); + PlexusConfiguration configuration = configurations.getChild("parameterWithGenerics"); + assertEquals("java.util.Collection", configuration.getAttribute("implementation")); + assertEquals("a,b,c", configuration.getAttribute("default-value")); + assertEquals("${customParam}", configuration.getValue()); + } } private void checkParameter(Parameter parameter) { diff --git a/pom.xml b/pom.xml index a4cfceb67..da6461eb5 100644 --- a/pom.xml +++ b/pom.xml @@ -90,7 +90,7 @@ 8 3.3.0 - 4.0.0-alpha-4 + 4.0.0-beta-4-SNAPSHOT 3.9.6 1.9.18 1.7.36 @@ -308,6 +308,21 @@ + + org.apache.maven.plugins + maven-enforcer-plugin + + + + ${maven.compiler.target} + + org.apache.maven:* + + + + true + + org.apache.maven.plugins maven-javadoc-plugin