You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by gn...@apache.org on 2022/02/24 16:04:38 UTC

[maven-plugin-tools] branch mvn4 updated: Switch a few core plugins to the new api

This is an automated email from the ASF dual-hosted git repository.

gnodet pushed a commit to branch mvn4
in repository https://gitbox.apache.org/repos/asf/maven-plugin-tools.git


The following commit(s) were added to refs/heads/mvn4 by this push:
     new 13fc5da  Switch a few core plugins to the new api
13fc5da is described below

commit 13fc5da37cd5f55a8fedf3699666de6110251b00
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Thu Feb 24 17:00:57 2022 +0100

    Switch a few core plugins to the new api
---
 maven-plugin-plugin/pom.xml                        |  4 +-
 .../src/main/java/fr/ca/MyMojo.java                |  3 +-
 .../scanner/DefaultMojoAnnotationsScanner.java     | 33 ++++++--
 .../scanner/MojoAnnotationsScanner.java            |  6 +-
 .../scanner/visitors/MojoClassVisitor.java         | 17 ++++-
 .../plugin/extractor/annotations/FooMojo.java      |  3 +-
 .../maven/tools/plugin/util/stubs/MojoStub.java    | 54 +------------
 .../plugin/generator/CachingOutputStream.java      | 42 ++++++----
 .../tools/plugin/generator/CachingWriter.java      | 66 ++++++++++++++++
 .../generator/PluginDescriptorGenerator.java       | 10 +--
 .../plugin/generator/PluginHelpGenerator.java      | 26 ++++---
 .../plugin/generator/PluginXdocGenerator.java      |  4 +-
 .../src/main/resources/help-class-source.vm        | 89 ++++++++++++++--------
 13 files changed, 222 insertions(+), 135 deletions(-)

diff --git a/maven-plugin-plugin/pom.xml b/maven-plugin-plugin/pom.xml
index 5af807f..e4c0436 100644
--- a/maven-plugin-plugin/pom.xml
+++ b/maven-plugin-plugin/pom.xml
@@ -38,12 +38,12 @@
   </description>
 
   <prerequisites>
-    <maven>${mavenVersion}</maven>
+    <maven>3.2.5</maven>
   </prerequisites>
 
   <properties>
     <doxiaVersion>2.0.0-M2-SNAPSHOT</doxiaVersion>
-    <doxiaSitetoolsVersion>2.0.0-M1-SNAPSHOT</doxiaSitetoolsVersion>
+    <doxiaSitetoolsVersion>2.0.0-M3-SNAPSHOT</doxiaSitetoolsVersion>
     <it.debug>true</it.debug>
   </properties>
 
diff --git a/maven-plugin-plugin/src/it/mplugin-272_java8/src/main/java/fr/ca/MyMojo.java b/maven-plugin-plugin/src/it/mplugin-272_java8/src/main/java/fr/ca/MyMojo.java
index 0775020..7ba2075 100644
--- a/maven-plugin-plugin/src/it/mplugin-272_java8/src/main/java/fr/ca/MyMojo.java
+++ b/maven-plugin-plugin/src/it/mplugin-272_java8/src/main/java/fr/ca/MyMojo.java
@@ -21,7 +21,6 @@ package fr.ca;
 
 import org.apache.maven.plugin.AbstractMojo;
 import org.apache.maven.plugin.MojoExecutionException;
-import org.apache.maven.plugin.MojoFailureException;
 import org.apache.maven.plugins.annotations.LifecyclePhase;
 import org.apache.maven.plugins.annotations.Mojo;
 
@@ -31,7 +30,7 @@ import org.apache.maven.plugins.annotations.Mojo;
 @Mojo(name="test-plugin",defaultPhase = LifecyclePhase.GENERATE_SOURCES)
 public class MyMojo extends AbstractMojo {
     @Override
-    public void execute() throws MojoExecutionException, MojoFailureException {
+    public void execute() throws MojoExecutionException {
 
     }
 }
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 d53848f..7e6285c 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
@@ -45,7 +45,9 @@ import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.Arrays;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.regex.Pattern;
@@ -61,9 +63,20 @@ public class DefaultMojoAnnotationsScanner
     extends AbstractLogEnabled
     implements MojoAnnotationsScanner
 {
+    public static final String MVN4_API = "org.apache.maven.api.plugin.annotations.";
+    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 MOJO_V3 = Mojo.class.getName();
+    public static final String EXECUTE_V3 = Execute.class.getName();
+    public static final String PARAMETER_V3 = Parameter.class.getName();
+    public static final String COMPONENT_V3 = Component.class.getName();
+
     // classes with a dash must be ignored
     private static final Pattern SCANNABLE_CLASS = Pattern.compile( "[^-]+\\.class" );
-    
+
     private Reflector reflector = new Reflector();
 
     @Override
@@ -266,7 +279,11 @@ public class DefaultMojoAnnotationsScanner
         try
         {
             // @Mojo annotation
-            MojoAnnotationVisitor mojoAnnotationVisitor = mojoClassVisitor.getAnnotationVisitor( Mojo.class );
+            MojoAnnotationVisitor mojoAnnotationVisitor = mojoClassVisitor.getAnnotationVisitor( MOJO_V3 );
+            if ( mojoAnnotationVisitor == null )
+            {
+                mojoAnnotationVisitor = mojoClassVisitor.getAnnotationVisitor( MOJO_V4 );
+            }
             if ( mojoAnnotationVisitor != null )
             {
                 MojoAnnotationContent mojoAnnotationContent = new MojoAnnotationContent();
@@ -275,7 +292,11 @@ public class DefaultMojoAnnotationsScanner
             }
 
             // @Execute annotation
-            mojoAnnotationVisitor = mojoClassVisitor.getAnnotationVisitor( Execute.class );
+            mojoAnnotationVisitor = mojoClassVisitor.getAnnotationVisitor( EXECUTE_V3 );
+            if ( mojoAnnotationVisitor == null )
+            {
+                mojoAnnotationVisitor = mojoClassVisitor.getAnnotationVisitor( EXECUTE_V4 );
+            }
             if ( mojoAnnotationVisitor != null )
             {
                 ExecuteAnnotationContent executeAnnotationContent = new ExecuteAnnotationContent();
@@ -284,7 +305,8 @@ public class DefaultMojoAnnotationsScanner
             }
 
             // @Parameter annotations
-            List<MojoFieldVisitor> mojoFieldVisitors = mojoClassVisitor.findFieldWithAnnotation( Parameter.class );
+            List<MojoFieldVisitor> mojoFieldVisitors = mojoClassVisitor.findFieldWithAnnotation(
+                    new HashSet<>( Arrays.asList( PARAMETER_V3, PARAMETER_V4 ) ) );
             for ( MojoFieldVisitor mojoFieldVisitor : mojoFieldVisitors )
             {
                 ParameterAnnotationContent parameterAnnotationContent =
@@ -300,7 +322,8 @@ public class DefaultMojoAnnotationsScanner
             }
 
             // @Component annotations
-            mojoFieldVisitors = mojoClassVisitor.findFieldWithAnnotation( Component.class );
+            mojoFieldVisitors = mojoClassVisitor.findFieldWithAnnotation(
+                    new HashSet<>( Arrays.asList( COMPONENT_V3, COMPONENT_V4 ) ) );
             for ( MojoFieldVisitor mojoFieldVisitor : mojoFieldVisitors )
             {
                 ComponentAnnotationContent componentAnnotationContent =
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 a5add2f..b112ed1 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
@@ -37,9 +37,11 @@ public interface MojoAnnotationsScanner
 {
     String ROLE = MojoAnnotationsScanner.class.getName();
 
-    List<String> CLASS_LEVEL_ANNOTATIONS = Arrays.asList( Mojo.class.getName(), Execute.class.getName() );
+    List<String> CLASS_LEVEL_ANNOTATIONS = Arrays.asList( Mojo.class.getName(), Execute.class.getName(),
+            "org.apache.maven.api.plugin.annotations.Mojo", "org.apache.maven.api.plugin.annotations.Execute" );
 
-    List<String> FIELD_LEVEL_ANNOTATIONS = Arrays.asList( Parameter.class.getName(), Component.class.getName() );
+    List<String> FIELD_LEVEL_ANNOTATIONS = Arrays.asList( Parameter.class.getName(), Component.class.getName(),
+            "org.apache.maven.api.plugin.annotations.Parameter", "org.apache.maven.api.plugin.annotations.Component" );
 
     /**
      * Scan classes for mojo annotations.
diff --git a/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/scanner/visitors/MojoClassVisitor.java b/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/scanner/visitors/MojoClassVisitor.java
index 6ebf4c6..1bf35c7 100644
--- a/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/scanner/visitors/MojoClassVisitor.java
+++ b/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/scanner/visitors/MojoClassVisitor.java
@@ -31,10 +31,11 @@ import org.objectweb.asm.Opcodes;
 import org.objectweb.asm.Type;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.Objects;
+import java.util.Set;
 
 /**
  * @author Olivier Lamy
@@ -74,7 +75,12 @@ public class MojoClassVisitor
 
     public MojoAnnotationVisitor getAnnotationVisitor( Class<?> annotation )
     {
-        return annotationVisitorMap.get( annotation.getName() );
+        return getAnnotationVisitor( annotation.getName() );
+    }
+
+    public MojoAnnotationVisitor getAnnotationVisitor( String name )
+    {
+        return annotationVisitorMap.get( name );
     }
 
     public void setAnnotationVisitorMap( Map<String, MojoAnnotationVisitor> annotationVisitorMap )
@@ -94,14 +100,17 @@ public class MojoClassVisitor
 
     public List<MojoFieldVisitor> findFieldWithAnnotation( Class<?> annotation )
     {
-        String annotationClassName = annotation.getName();
+        return findFieldWithAnnotation( Collections.singleton( annotation.getName() ) );
+    }
 
+    public List<MojoFieldVisitor> findFieldWithAnnotation( Set<String> annotationClassNames )
+    {
         List<MojoFieldVisitor> mojoFieldVisitors = new ArrayList<MojoFieldVisitor>();
 
         for ( MojoFieldVisitor mojoFieldVisitor : this.fieldVisitors )
         {
             MojoAnnotationVisitor mojoAnnotationVisitor = mojoFieldVisitor.getMojoAnnotationVisitor();
-            if ( mojoAnnotationVisitor != null && Objects.equals( annotationClassName,
+            if ( mojoAnnotationVisitor != null && annotationClassNames.contains(
                                                                       mojoAnnotationVisitor.getAnnotationClassName() ) )
             {
                 mojoFieldVisitors.add( mojoFieldVisitor );
diff --git a/maven-plugin-tools-annotations/src/test/java/org/apache/maven/tools/plugin/extractor/annotations/FooMojo.java b/maven-plugin-tools-annotations/src/test/java/org/apache/maven/tools/plugin/extractor/annotations/FooMojo.java
index 3543dd2..fca58ea 100644
--- a/maven-plugin-tools-annotations/src/test/java/org/apache/maven/tools/plugin/extractor/annotations/FooMojo.java
+++ b/maven-plugin-tools-annotations/src/test/java/org/apache/maven/tools/plugin/extractor/annotations/FooMojo.java
@@ -21,7 +21,6 @@ package org.apache.maven.tools.plugin.extractor.annotations;
 
 import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
 import org.apache.maven.plugin.MojoExecutionException;
-import org.apache.maven.plugin.MojoFailureException;
 import org.apache.maven.plugins.annotations.Component;
 import org.apache.maven.plugins.annotations.Execute;
 import org.apache.maven.plugins.annotations.LifecyclePhase;
@@ -66,7 +65,7 @@ public class FooMojo
 
     @Override
     public void execute()
-        throws MojoExecutionException, MojoFailureException
+        throws MojoExecutionException
     {
         // nothing
     }
diff --git a/maven-plugin-tools-api/src/test/java/org/apache/maven/tools/plugin/util/stubs/MojoStub.java b/maven-plugin-tools-api/src/test/java/org/apache/maven/tools/plugin/util/stubs/MojoStub.java
index d652afa..567b3a1 100644
--- a/maven-plugin-tools-api/src/test/java/org/apache/maven/tools/plugin/util/stubs/MojoStub.java
+++ b/maven-plugin-tools-api/src/test/java/org/apache/maven/tools/plugin/util/stubs/MojoStub.java
@@ -23,7 +23,6 @@ import java.util.Map;
 
 import org.apache.maven.plugin.AbstractMojo;
 import org.apache.maven.plugin.MojoExecutionException;
-import org.apache.maven.plugin.MojoFailureException;
 import org.apache.maven.plugin.logging.Log;
 
 /**
@@ -36,13 +35,6 @@ public class MojoStub
 {
     /** {@inheritDoc} */
     @Override
-    public Log getLog()
-    {
-        return super.getLog();
-    }
-
-    /** {@inheritDoc} */
-    @Override
     public Map getPluginContext()
     {
         return super.getPluginContext();
@@ -50,13 +42,6 @@ public class MojoStub
 
     /** {@inheritDoc} */
     @Override
-    public void setLog( Log log )
-    {
-        super.setLog( log );
-    }
-
-    /** {@inheritDoc} */
-    @Override
     public void setPluginContext( Map pluginContext )
     {
         super.setPluginContext( pluginContext );
@@ -64,45 +49,8 @@ public class MojoStub
 
     /** {@inheritDoc} */
     @Override
-    protected Object clone()
-        throws CloneNotSupportedException
-    {
-        return super.clone();
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public boolean equals( Object obj )
-    {
-        return super.equals( obj );
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    protected void finalize()
-        throws Throwable
-    {
-        super.finalize();
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public int hashCode()
-    {
-        return super.hashCode();
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public String toString()
-    {
-        return super.toString();
-    }
-
-    /** {@inheritDoc} */
-    @Override
     public void execute()
-        throws MojoExecutionException, MojoFailureException
+        throws MojoExecutionException
     {
 
     }
diff --git a/maven-plugin-plugin/src/it/mplugin-272_java8/src/main/java/fr/ca/MyMojo.java b/maven-plugin-tools-generators/src/main/java/org/apache/maven/tools/plugin/generator/CachingOutputStream.java
similarity index 52%
copy from maven-plugin-plugin/src/it/mplugin-272_java8/src/main/java/fr/ca/MyMojo.java
copy to maven-plugin-tools-generators/src/main/java/org/apache/maven/tools/plugin/generator/CachingOutputStream.java
index 0775020..98961fa 100644
--- a/maven-plugin-plugin/src/it/mplugin-272_java8/src/main/java/fr/ca/MyMojo.java
+++ b/maven-plugin-tools-generators/src/main/java/org/apache/maven/tools/plugin/generator/CachingOutputStream.java
@@ -1,4 +1,4 @@
-package fr.ca;
+package org.apache.maven.tools.plugin.generator;
 
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -19,19 +19,35 @@ package fr.ca;
  * under the License.
  */
 
-import org.apache.maven.plugin.AbstractMojo;
-import org.apache.maven.plugin.MojoExecutionException;
-import org.apache.maven.plugin.MojoFailureException;
-import org.apache.maven.plugins.annotations.LifecyclePhase;
-import org.apache.maven.plugins.annotations.Mojo;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.Objects;
 
-/**
- * Created by clement.agarini on 04/08/14.
- */
-@Mojo(name="test-plugin",defaultPhase = LifecyclePhase.GENERATE_SOURCES)
-public class MyMojo extends AbstractMojo {
-    @Override
-    public void execute() throws MojoExecutionException, MojoFailureException {
+public class CachingOutputStream extends ByteArrayOutputStream
+{
+    private final Path path;
+
+    public CachingOutputStream( Path path )
+    {
+        this.path = Objects.requireNonNull( path );
+    }
 
+    @Override
+    public void close() throws IOException
+    {
+        byte[] data = toByteArray();
+        if ( Files.exists( path ) )
+        {
+            byte[] old = Files.readAllBytes( path );
+            if ( Arrays.equals( old, data ) )
+            {
+                return;
+            }
+        }
+        Files.write( path, data );
     }
+
 }
diff --git a/maven-plugin-tools-generators/src/main/java/org/apache/maven/tools/plugin/generator/CachingWriter.java b/maven-plugin-tools-generators/src/main/java/org/apache/maven/tools/plugin/generator/CachingWriter.java
new file mode 100644
index 0000000..a994965
--- /dev/null
+++ b/maven-plugin-tools-generators/src/main/java/org/apache/maven/tools/plugin/generator/CachingWriter.java
@@ -0,0 +1,66 @@
+package org.apache.maven.tools.plugin.generator;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Objects;
+
+public class CachingWriter extends StringWriter
+{
+    private final Path path;
+    private final Charset charset;
+
+    public CachingWriter( Path path, Charset charset )
+    {
+        this.path = Objects.requireNonNull( path );
+        this.charset = Objects.requireNonNull( charset );
+    }
+
+    @Override
+    public void close() throws IOException
+    {
+        String str = getBuffer().toString();
+        if ( Files.exists( path ) )
+        {
+            String old = readString( path, charset );
+            if ( str.equals( old ) )
+            {
+                return;
+            }
+        }
+        writeString( path, str, charset );
+    }
+
+    private static String readString( Path path, Charset charset ) throws IOException
+    {
+        byte[] ba = Files.readAllBytes( path );
+        return new String( ba, charset );
+    }
+
+    private static void writeString( Path path, String str, Charset charset ) throws IOException
+    {
+        byte[] ba = str.getBytes( charset );
+        Files.write( path, ba );
+    }
+}
diff --git a/maven-plugin-tools-generators/src/main/java/org/apache/maven/tools/plugin/generator/PluginDescriptorGenerator.java b/maven-plugin-tools-generators/src/main/java/org/apache/maven/tools/plugin/generator/PluginDescriptorGenerator.java
index 6e777c0..901412b 100644
--- a/maven-plugin-tools-generators/src/main/java/org/apache/maven/tools/plugin/generator/PluginDescriptorGenerator.java
+++ b/maven-plugin-tools-generators/src/main/java/org/apache/maven/tools/plugin/generator/PluginDescriptorGenerator.java
@@ -22,9 +22,7 @@ package org.apache.maven.tools.plugin.generator;
 import static java.nio.charset.StandardCharsets.UTF_8;
 
 import java.io.File;
-import java.io.FileOutputStream;
 import java.io.IOException;
-import java.io.OutputStreamWriter;
 import java.io.Writer;
 import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
@@ -104,16 +102,12 @@ public class PluginDescriptorGenerator
     {
         PluginDescriptor pluginDescriptor = request.getPluginDescriptor();
 
-        if ( destinationFile.exists() )
-        {
-            destinationFile.delete();
-        }
-        else if ( !destinationFile.getParentFile().exists() )
+        if ( !destinationFile.getParentFile().exists() )
         {
             destinationFile.getParentFile().mkdirs();
         }
 
-        try ( Writer writer = new OutputStreamWriter( new FileOutputStream( destinationFile ), UTF_8 ) )
+        try ( Writer writer = new CachingWriter( destinationFile.toPath(), UTF_8 ) )
         {
             XMLWriter w = new PrettyPrintXMLWriter( writer, UTF_8.name(), null );
 
diff --git a/maven-plugin-tools-generators/src/main/java/org/apache/maven/tools/plugin/generator/PluginHelpGenerator.java b/maven-plugin-tools-generators/src/main/java/org/apache/maven/tools/plugin/generator/PluginHelpGenerator.java
index 2c3af58..aefb818 100644
--- a/maven-plugin-tools-generators/src/main/java/org/apache/maven/tools/plugin/generator/PluginHelpGenerator.java
+++ b/maven-plugin-tools-generators/src/main/java/org/apache/maven/tools/plugin/generator/PluginHelpGenerator.java
@@ -30,7 +30,6 @@ import org.apache.velocity.VelocityContext;
 import org.codehaus.plexus.logging.AbstractLogEnabled;
 import org.codehaus.plexus.logging.Logger;
 import org.codehaus.plexus.logging.console.ConsoleLogger;
-import org.codehaus.plexus.util.FileUtils;
 import org.codehaus.plexus.util.IOUtil;
 import org.codehaus.plexus.util.PropertyUtils;
 import org.codehaus.plexus.util.StringUtils;
@@ -44,14 +43,13 @@ import org.objectweb.asm.commons.SimpleRemapper;
 
 import java.io.File;
 import java.io.FileInputStream;
-import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
-import java.io.OutputStreamWriter;
 import java.io.PrintWriter;
 import java.io.Reader;
 import java.io.StringWriter;
+import java.io.Writer;
 import java.nio.charset.Charset;
 import java.util.List;
 import java.util.Properties;
@@ -92,6 +90,8 @@ public class PluginHelpGenerator
 
     private boolean useAnnotations;
 
+    private boolean useMaven4Api;
+
     private VelocityComponent velocityComponent;
 
     /**
@@ -142,6 +142,9 @@ public class PluginHelpGenerator
         useAnnotations = request.getProject().getArtifactMap().containsKey(
             "org.apache.maven.plugin-tools:maven-plugin-annotations" );
 
+        useMaven4Api = request.getProject().getArtifactMap().containsKey(
+                "org.apache.maven:maven-core-api" );
+
         try
         {
             String sourcePath = helpImplementation.replace( '.', File.separatorChar ) + ".java";
@@ -152,7 +155,10 @@ public class PluginHelpGenerator
             String helpClassSources =
                 getHelpClassSources( getPluginHelpPath( request.getProject() ), pluginDescriptor );
 
-            FileUtils.fileWrite( helpClass, request.getEncoding(), helpClassSources );
+            try ( Writer writer = new CachingWriter( helpClass.toPath(), Charset.forName( request.getEncoding() ) ) )
+            {
+                writer.write( helpClassSources );
+            }
         }
         catch ( IOException e )
         {
@@ -198,6 +204,7 @@ public class PluginHelpGenerator
         properties.put( "artifactId", pluginDescriptor.getArtifactId() );
         properties.put( "goalPrefix", pluginDescriptor.getGoalPrefix() );
         properties.put( "useAnnotations", useAnnotations );
+        properties.put( "useMaven4Api", useMaven4Api );
 
         StringWriter stringWriter = new StringWriter();
 
@@ -256,9 +263,9 @@ public class PluginHelpGenerator
             tmpPropertiesFile.getParentFile().mkdirs();
         }
 
-        try ( FileOutputStream fos = new FileOutputStream( tmpPropertiesFile ) )
+        try ( Writer writer = new CachingWriter( tmpPropertiesFile.toPath(), UTF_8 ) )
         {
-            properties.store( fos, "maven plugin help mojo generation informations" );
+            properties.store( writer, "maven plugin help mojo generation informations" );
         }
         catch ( IOException e )
         {
@@ -365,9 +372,8 @@ public class PluginHelpGenerator
             Charset encoding = Charset.forName( request.getEncoding() );
             try ( Reader sourceReader = new InputStreamReader( new FileInputStream( helpSourceFile ), //
                                                               encoding ); //
-                 PrintWriter sourceWriter = new PrintWriter(
-                     new OutputStreamWriter( new FileOutputStream( helpSourceFileNew ), //
-                                             encoding ) ) )
+                  PrintWriter sourceWriter = new PrintWriter( new CachingWriter(
+                         helpSourceFileNew.toPath(), encoding ) ) )
             {
                 sourceWriter.println( "package " + destinationPackage + ";" );
                 IOUtil.copy( sourceReader, sourceWriter );
@@ -414,7 +420,7 @@ public class PluginHelpGenerator
         }
 
         byte[] renamedClass = cw.toByteArray();
-        try ( FileOutputStream fos = new FileOutputStream( rewriteHelpClassFile ) )
+        try ( CachingOutputStream fos = new CachingOutputStream( rewriteHelpClassFile.toPath() ) )
         {
             fos.write( renamedClass );
         }
diff --git a/maven-plugin-tools-generators/src/main/java/org/apache/maven/tools/plugin/generator/PluginXdocGenerator.java b/maven-plugin-tools-generators/src/main/java/org/apache/maven/tools/plugin/generator/PluginXdocGenerator.java
index c17ec59..dcaa592 100644
--- a/maven-plugin-tools-generators/src/main/java/org/apache/maven/tools/plugin/generator/PluginXdocGenerator.java
+++ b/maven-plugin-tools-generators/src/main/java/org/apache/maven/tools/plugin/generator/PluginXdocGenerator.java
@@ -31,9 +31,7 @@ import org.codehaus.plexus.util.xml.PrettyPrintXMLWriter;
 import org.codehaus.plexus.util.xml.XMLWriter;
 
 import java.io.File;
-import java.io.FileOutputStream;
 import java.io.IOException;
-import java.io.OutputStreamWriter;
 import java.io.PrintWriter;
 import java.io.Writer;
 import java.text.MessageFormat;
@@ -133,7 +131,7 @@ public class PluginXdocGenerator
         throws IOException
     {
         File outputFile = new File( destinationDirectory, getMojoFilename( mojoDescriptor, "xml" ) );
-        try ( Writer writer = new OutputStreamWriter( new FileOutputStream( outputFile ), UTF_8 ) )
+        try ( Writer writer = new CachingWriter( outputFile.toPath(), UTF_8 ) )
         {
             XMLWriter w = new PrettyPrintXMLWriter( new PrintWriter( writer ), UTF_8.name(), null );
             writeBody( mojoDescriptor, w );
diff --git a/maven-plugin-tools-generators/src/main/resources/help-class-source.vm b/maven-plugin-tools-generators/src/main/resources/help-class-source.vm
index 7dd7209..8a0d6b5 100644
--- a/maven-plugin-tools-generators/src/main/resources/help-class-source.vm
+++ b/maven-plugin-tools-generators/src/main/resources/help-class-source.vm
@@ -1,3 +1,10 @@
+#if ( $useMaven4Api )
+#set ( $mojoException = "MojoException" )
+#set ( $logger = "logger" )
+#else
+#set ( $mojoException = "MojoExecutionException" )
+#set ( $logger = "getLog()" )
+#end
 ## 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
@@ -5,9 +12,9 @@
 ## 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
@@ -18,13 +25,23 @@
 package ${helpPackageName};
 #end
 
+#if( $useMaven4Api )
+import org.apache.maven.api.plugin.MojoException;
+import org.apache.maven.api.plugin.annotations.Mojo;
+import org.apache.maven.api.plugin.annotations.Parameter;
+#else
 import org.apache.maven.plugin.AbstractMojo;
 import org.apache.maven.plugin.MojoExecutionException;
 #if ( $useAnnotations )
 import org.apache.maven.plugins.annotations.Mojo;
 import org.apache.maven.plugins.annotations.Parameter;
 #end
+#end
 
+#if ( $useMaven4Api )
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+#end
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 import org.w3c.dom.Node;
@@ -43,26 +60,36 @@ import java.util.List;
  * Display help information on ${artifactId}.<br>
  * Call <code>mvn ${goalPrefix}:help -Ddetail=true -Dgoal=&lt;goal-name&gt;</code> to display parameter details.
  * @author maven-plugin-tools
-#if ( !$useAnnotations )     
+#if ( !$useAnnotations )
  * @goal help
  * @requiresProject false
  * @threadSafe
 #end
  */
-#if ( $useAnnotations )
+#if ( $useMaven4Api )
+@Mojo( name = "help", requiresProject = false )
+#elseif ( $useAnnotations )
 @Mojo( name = "help", requiresProject = false, threadSafe = true )
 #end
 public class HelpMojo
+#if ( $useMaven4Api )
+    implements org.apache.maven.api.plugin.Mojo
+#else
     extends AbstractMojo
+#end
 {
+#if ( $useMaven4Api )
+    private final Logger logger = LoggerFactory.getLogger( getClass() );
+
+#end
     /**
      * If <code>true</code>, display all settable properties for each goal.
      *
-#if ( !$useAnnotations )     
+#if ( !$useAnnotations )
      * @parameter property="detail" default-value="false"
 #end
      */
-#if ( $useAnnotations )     
+#if ( $useAnnotations || $useMaven4Api )
     @Parameter( property = "detail", defaultValue = "false" )
 #end
     private boolean detail;
@@ -70,23 +97,23 @@ public class HelpMojo
     /**
      * The name of the goal for which to show help. If unspecified, all goals will be displayed.
      *
-#if ( !$useAnnotations )     
+#if ( !$useAnnotations )
      * @parameter property="goal"
 #end
      */
-#if ( $useAnnotations )     
+#if ( $useAnnotations || $useMaven4Api )
     @Parameter( property = "goal" )
-#end    
+#end
     private java.lang.String goal;
 
     /**
      * The maximum length of a display line, should be positive.
      *
-#if ( !$useAnnotations )     
+#if ( !$useAnnotations )
      * @parameter property="lineLength" default-value="80"
 #end
      */
-#if ( $useAnnotations )     
+#if ( $useAnnotations || $useMaven4Api )
     @Parameter( property = "lineLength", defaultValue = "80" )
 #end
     private int lineLength;
@@ -94,11 +121,11 @@ public class HelpMojo
     /**
      * The number of spaces per indentation level, should be positive.
      *
-#if ( !$useAnnotations )     
+#if ( !$useAnnotations )
      * @parameter property="indentSize" default-value="2"
 #end
      */
-#if ( $useAnnotations )     
+#if ( $useAnnotations || $useMaven4Api )
     @Parameter( property = "indentSize", defaultValue = "2" )
 #end
     private int indentSize;
@@ -110,9 +137,9 @@ public class HelpMojo
     private static final int DEFAULT_LINE_LENGTH = 80;
 
     private Document build()
-        throws MojoExecutionException
+        throws ${mojoException}
     {
-        getLog().debug( "load plugin-help.xml: " + PLUGIN_HELP_PATH );
+        ${logger}.debug( "load plugin-help.xml: " + PLUGIN_HELP_PATH );
         try ( InputStream is = getClass().getResourceAsStream( PLUGIN_HELP_PATH ) )
         {
             DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
@@ -121,15 +148,15 @@ public class HelpMojo
         }
         catch ( IOException e )
         {
-            throw new MojoExecutionException( e.getMessage(), e );
+            throw new ${mojoException}( e.getMessage(), e );
         }
         catch ( ParserConfigurationException e )
         {
-            throw new MojoExecutionException( e.getMessage(), e );
+            throw new ${mojoException}( e.getMessage(), e );
         }
         catch ( SAXException e )
         {
-            throw new MojoExecutionException( e.getMessage(), e );
+            throw new ${mojoException}( e.getMessage(), e );
         }
     }
 
@@ -138,16 +165,16 @@ public class HelpMojo
      */
     @Override
     public void execute()
-        throws MojoExecutionException
+        throws ${mojoException}
     {
         if ( lineLength <= 0 )
         {
-            getLog().warn( "The parameter 'lineLength' should be positive, using '80' as default." );
+            ${logger}.warn( "The parameter 'lineLength' should be positive, using '80' as default." );
             lineLength = DEFAULT_LINE_LENGTH;
         }
         if ( indentSize <= 0 )
         {
-            getLog().warn( "The parameter 'indentSize' should be positive, using '2' as default." );
+            ${logger}.warn( "The parameter 'indentSize' should be positive, using '2' as default." );
             indentSize = 2;
         }
 
@@ -196,9 +223,9 @@ public class HelpMojo
             writeGoal( sb, goalPrefix, (Element) mojo );
         }
 
-        if ( getLog().isInfoEnabled() )
+        if ( ${logger}.isInfoEnabled() )
         {
-            getLog().info( sb.toString() );
+            ${logger}.info( sb.toString() );
         }
     }
 
@@ -209,22 +236,22 @@ public class HelpMojo
     }
 
     private static String getValue( Node node, String elementName )
-        throws MojoExecutionException
+        throws ${mojoException}
     {
         return getSingleChild( node, elementName ).getTextContent();
     }
 
     private static Node getSingleChild( Node node, String elementName )
-        throws MojoExecutionException
+        throws ${mojoException}
     {
         List<Node> namedChild = findNamedChild( node, elementName );
         if ( namedChild.isEmpty() )
         {
-            throw new MojoExecutionException( "Could not find " + elementName + " in plugin-help.xml" );
+            throw new ${mojoException}( "Could not find " + elementName + " in plugin-help.xml" );
         }
         if ( namedChild.size() > 1 )
         {
-            throw new MojoExecutionException( "Multiple " + elementName + " in plugin-help.xml" );
+            throw new ${mojoException}( "Multiple " + elementName + " in plugin-help.xml" );
         }
         return namedChild.get( 0 );
     }
@@ -245,7 +272,7 @@ public class HelpMojo
     }
 
     private static Node findSingleChild( Node node, String elementName )
-        throws MojoExecutionException
+        throws ${mojoException}
     {
         List<Node> elementsByTagName = findNamedChild( node, elementName );
         if ( elementsByTagName.isEmpty() )
@@ -254,13 +281,13 @@ public class HelpMojo
         }
         if ( elementsByTagName.size() > 1 )
         {
-            throw new MojoExecutionException( "Multiple " + elementName + "in plugin-help.xml" );
+            throw new ${mojoException}( "Multiple " + elementName + "in plugin-help.xml" );
         }
         return elementsByTagName.get( 0 );
     }
 
     private void writeGoal( StringBuilder sb, String goalPrefix, Element mojo )
-        throws MojoExecutionException
+        throws ${mojoException}
     {
         String mojoGoal = getValue( mojo, "goal" );
         Node configurationElement = findSingleChild( mojo, "configuration" );
@@ -300,7 +327,7 @@ public class HelpMojo
     }
 
     private void writeParameter( StringBuilder sb, Node parameter, Node configurationElement )
-        throws MojoExecutionException
+        throws ${mojoException}
     {
         String parameterName = getValue( parameter, "name" );
         String parameterDescription = getValue( parameter, "description" );