View Javadoc
1   package org.apache.maven.plugin.compiler;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import org.apache.maven.artifact.Artifact;
23  import org.apache.maven.artifact.DefaultArtifact;
24  import org.apache.maven.artifact.handler.ArtifactHandler;
25  import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
26  import org.apache.maven.artifact.resolver.ArtifactResolutionRequest;
27  import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
28  import org.apache.maven.artifact.resolver.ResolutionErrorHandler;
29  import org.apache.maven.artifact.versioning.VersionRange;
30  import org.apache.maven.execution.MavenSession;
31  import org.apache.maven.plugin.AbstractMojo;
32  import org.apache.maven.plugin.MojoExecution;
33  import org.apache.maven.plugin.MojoExecutionException;
34  import org.apache.maven.plugins.annotations.Component;
35  import org.apache.maven.plugins.annotations.Parameter;
36  import org.apache.maven.project.MavenProject;
37  import org.apache.maven.repository.RepositorySystem;
38  import org.apache.maven.shared.incremental.IncrementalBuildHelper;
39  import org.apache.maven.shared.incremental.IncrementalBuildHelperRequest;
40  import org.apache.maven.shared.utils.ReaderFactory;
41  import org.apache.maven.shared.utils.StringUtils;
42  import org.apache.maven.shared.utils.io.FileUtils;
43  import org.apache.maven.toolchain.Toolchain;
44  import org.apache.maven.toolchain.ToolchainManager;
45  import org.codehaus.plexus.compiler.Compiler;
46  import org.codehaus.plexus.compiler.CompilerConfiguration;
47  import org.codehaus.plexus.compiler.CompilerError;
48  import org.codehaus.plexus.compiler.CompilerException;
49  import org.codehaus.plexus.compiler.CompilerMessage;
50  import org.codehaus.plexus.compiler.CompilerNotImplementedException;
51  import org.codehaus.plexus.compiler.CompilerOutputStyle;
52  import org.codehaus.plexus.compiler.CompilerResult;
53  import org.codehaus.plexus.compiler.manager.CompilerManager;
54  import org.codehaus.plexus.compiler.manager.NoSuchCompilerException;
55  import org.codehaus.plexus.compiler.util.scan.InclusionScanException;
56  import org.codehaus.plexus.compiler.util.scan.SourceInclusionScanner;
57  import org.codehaus.plexus.compiler.util.scan.mapping.SingleTargetSourceMapping;
58  import org.codehaus.plexus.compiler.util.scan.mapping.SourceMapping;
59  import org.codehaus.plexus.compiler.util.scan.mapping.SuffixMapping;
60  
61  import java.io.File;
62  import java.lang.reflect.Method;
63  import java.util.ArrayList;
64  import java.util.Date;
65  import java.util.HashSet;
66  import java.util.LinkedHashMap;
67  import java.util.List;
68  import java.util.Map;
69  import java.util.Set;
70  
71  /**
72   * TODO: At least one step could be optimized, currently the plugin will do two
73   * scans of all the source code if the compiler has to have the entire set of
74   * sources. This is currently the case for at least the C# compiler and most
75   * likely all the other .NET compilers too.
76   *
77   * @author others
78   * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
79   * @version $Id: AbstractCompilerMojo.html 977871 2016-01-16 21:47:39Z agudian $
80   * @since 2.0
81   */
82  public abstract class AbstractCompilerMojo
83      extends AbstractMojo
84  {
85  
86      // ----------------------------------------------------------------------
87      // Configurables
88      // ----------------------------------------------------------------------
89  
90      /**
91       * Indicates whether the build will continue even if there are compilation errors.
92       *
93       * @since 2.0.2
94       */
95      @Parameter( property = "maven.compiler.failOnError", defaultValue = "true" )
96      private boolean failOnError = true;
97  
98      /**
99       * Set to <code>true</code> to include debugging information in the compiled class files.
100      */
101     @Parameter( property = "maven.compiler.debug", defaultValue = "true" )
102     private boolean debug = true;
103 
104     /**
105      * Set to <code>true</code> to show messages about what the compiler is doing.
106      */
107     @Parameter( property = "maven.compiler.verbose", defaultValue = "false" )
108     private boolean verbose;
109 
110     /**
111      * Sets whether to show source locations where deprecated APIs are used.
112      */
113     @Parameter( property = "maven.compiler.showDeprecation", defaultValue = "false" )
114     private boolean showDeprecation;
115 
116     /**
117      * Set to <code>true</code> to optimize the compiled code using the compiler's optimization methods.
118      */
119     @Parameter( property = "maven.compiler.optimize", defaultValue = "false" )
120     private boolean optimize;
121 
122     /**
123      * Set to <code>true</code> to show compilation warnings.
124      */
125     @Parameter( property = "maven.compiler.showWarnings", defaultValue = "false" )
126     private boolean showWarnings;
127 
128     /**
129      * The -source argument for the Java compiler.
130      */
131     @Parameter( property = "maven.compiler.source", defaultValue = "1.5" )
132     protected String source;
133 
134     /**
135      * The -target argument for the Java compiler.
136      */
137     @Parameter( property = "maven.compiler.target", defaultValue = "1.5" )
138     protected String target;
139 
140     /**
141      * The -encoding argument for the Java compiler.
142      *
143      * @since 2.1
144      */
145     @Parameter( property = "encoding", defaultValue = "${project.build.sourceEncoding}" )
146     private String encoding;
147 
148     /**
149      * Sets the granularity in milliseconds of the last modification
150      * date for testing whether a source needs recompilation.
151      */
152     @Parameter( property = "lastModGranularityMs", defaultValue = "0" )
153     private int staleMillis;
154 
155     /**
156      * The compiler id of the compiler to use. See this
157      * <a href="non-javac-compilers.html">guide</a> for more information.
158      */
159     @Parameter( property = "maven.compiler.compilerId", defaultValue = "javac" )
160     private String compilerId;
161 
162     /**
163      * Version of the compiler to use, ex. "1.3", "1.5", if {@link #fork} is set to <code>true</code>.
164      */
165     @Parameter( property = "maven.compiler.compilerVersion" )
166     private String compilerVersion;
167 
168     /**
169      * Allows running the compiler in a separate process.
170      * If <code>false</code> it uses the built in compiler, while if <code>true</code> it will use an executable.
171      */
172     @Parameter( property = "maven.compiler.fork", defaultValue = "false" )
173     private boolean fork;
174 
175     /**
176      * Initial size, in megabytes, of the memory allocation pool, ex. "64", "64m"
177      * if {@link #fork} is set to <code>true</code>.
178      *
179      * @since 2.0.1
180      */
181     @Parameter( property = "maven.compiler.meminitial" )
182     private String meminitial;
183 
184     /**
185      * Sets the maximum size, in megabytes, of the memory allocation pool, ex. "128", "128m"
186      * if {@link #fork} is set to <code>true</code>.
187      *
188      * @since 2.0.1
189      */
190     @Parameter( property = "maven.compiler.maxmem" )
191     private String maxmem;
192 
193     /**
194      * Sets the executable of the compiler to use when {@link #fork} is <code>true</code>.
195      */
196     @Parameter( property = "maven.compiler.executable" )
197     private String executable;
198 
199     /**
200      * <p>
201      * Sets whether annotation processing is performed or not. Only applies to JDK 1.6+
202      * If not set, both compilation and annotation processing are performed at the same time.
203      * </p>
204      * <p>Allowed values are:</p>
205      * <ul>
206      * <li><code>none</code> - no annotation processing is performed.</li>
207      * <li><code>only</code> - only annotation processing is done, no compilation.</li>
208      * </ul>
209      *
210      * @since 2.2
211      */
212     @Parameter
213     private String proc;
214 
215     /**
216      * <p>
217      * Names of annotation processors to run. Only applies to JDK 1.6+
218      * If not set, the default annotation processors discovery process applies.
219      * </p>
220      *
221      * @since 2.2
222      */
223     @Parameter
224     private String[] annotationProcessors;
225 
226     /**
227      * <p>
228      * Classpath elements to supply as annotation processor path. If specified, the compiler will detect annotation
229      * processors only in those classpath elements. If omitted, the default classpath is used to detect annotation
230      * processors. The detection itself depends on the configuration of {@code annotationProcessors}.
231      * </p>
232      * <p>
233      * Each classpath element is specified using their Maven coordinates (groupId, artifactId, version, classifier,
234      * type). Transitive dependencies are added automatically. Example:
235      * </p>
236      *
237      * <pre>
238      * &lt;configuration&gt;
239      *   &lt;annotationProcessorPaths&gt;
240      *     &lt;path&gt;
241      *       &lt;groupId&gt;org.sample&lt;/groupId&gt;
242      *       &lt;artifactId&gt;sample-annotation-processor&lt;/artifactId&gt;
243      *       &lt;version&gt;1.2.3&lt;/version&gt;
244      *     &lt;/path&gt;
245      *     &lt;!-- ... more ... --&gt;
246      *   &lt;/annotationProcessorPaths&gt;
247      * &lt;/configuration&gt;
248      * </pre>
249      *
250      * @since 3.5
251      */
252     @Parameter
253     private List<DependencyCoordinate> annotationProcessorPaths;
254 
255     /**
256      * <p>
257      * Sets the arguments to be passed to the compiler (prepending a dash) if {@link #fork} is set to <code>true</code>.
258      * </p>
259      * <p>
260      * This is because the list of valid arguments passed to a Java compiler varies based on the compiler version.
261      * </p>
262      * <p>
263      * To pass <code>-Xmaxerrs 1000 -Xlint -Xlint:-path -Averbose=true</code> you should include the following:
264      * </p>
265      *
266      * <pre>
267      * &lt;compilerArguments&gt;
268      *   &lt;Xmaxerrs&gt;1000&lt;/Xmaxerrs&gt;
269      *   &lt;Xlint/&gt;
270      *   &lt;Xlint:-path/&gt;
271      *   &lt;Averbose&gt;true&lt;/Averbose&gt;
272      * &lt;/compilerArguments&gt;
273      * </pre>
274      *
275      * @since 2.0.1
276      * @deprecated use {@link #compilerArgs} instead.
277      */
278     @Parameter
279     @Deprecated
280     protected Map<String, String> compilerArguments;
281 
282     /**
283      * <p>
284      * Sets the arguments to be passed to the compiler if {@link #fork} is set to <code>true</code>.
285      * Example:
286      * <pre>
287      * &lt;compilerArgs&gt;
288      *   &lt;arg&gt;-Xmaxerrs=1000&lt;/arg&gt;
289      *   &lt;arg&gt;-Xlint&lt;/arg&gt;
290      *   &lt;arg&gt;-J-Duser.language=en_us&lt;/arg&gt;
291      * &lt;/compilerArgs&gt;
292      * </pre>
293      *
294      * @since 3.1
295      */
296     @Parameter
297     protected List<String> compilerArgs;
298 
299     /**
300      * <p>
301      * Sets the unformatted single argument string to be passed to the compiler if {@link #fork} is set to
302      * <code>true</code>. To pass multiple arguments such as <code>-Xmaxerrs 1000</code> (which are actually two
303      * arguments) you have to use {@link #compilerArguments}.
304      * </p>
305      * <p>
306      * This is because the list of valid arguments passed to a Java compiler varies based on the compiler version.
307      * </p>
308      */
309     @Parameter
310     protected String compilerArgument;
311 
312     /**
313      * Sets the name of the output file when compiling a set of
314      * sources to a single file.
315      * <p/>
316      * expression="${project.build.finalName}"
317      */
318     @Parameter
319     private String outputFileName;
320 
321     /**
322      * Keyword list to be appended to the <code>-g</code> command-line switch. Legal values are none or a
323      * comma-separated list of the following keywords: <code>lines</code>, <code>vars</code>, and <code>source</code>.
324      * If debug level is not specified, by default, nothing will be appended to <code>-g</code>.
325      * If debug is not turned on, this attribute will be ignored.
326      *
327      * @since 2.1
328      */
329     @Parameter( property = "maven.compiler.debuglevel" )
330     private String debuglevel;
331 
332     /**
333      *
334      */
335     @Component
336     private ToolchainManager toolchainManager;
337 
338     // ----------------------------------------------------------------------
339     // Read-only parameters
340     // ----------------------------------------------------------------------
341 
342     /**
343      * The directory to run the compiler from if fork is true.
344      */
345     @Parameter( defaultValue = "${basedir}", required = true, readonly = true )
346     private File basedir;
347 
348     /**
349      * The target directory of the compiler if fork is true.
350      */
351     @Parameter( defaultValue = "${project.build.directory}", required = true, readonly = true )
352     private File buildDirectory;
353 
354     /**
355      * Plexus compiler manager.
356      */
357     @Component
358     private CompilerManager compilerManager;
359 
360     /**
361      * The current build session instance. This is used for toolchain manager API calls.
362      */
363     @Parameter( defaultValue = "${session}", readonly = true, required = true )
364     private MavenSession session;
365 
366     /**
367      * The current project instance. This is used for propagating generated-sources paths as compile/testCompile source
368      * roots.
369      */
370     @Parameter( defaultValue = "${project}", readonly = true, required = true )
371     private MavenProject project;
372 
373     /**
374      * Strategy to re use javacc class created:
375      * <ul>
376      * <li><code>reuseCreated</code> (default): will reuse already created but in case of multi-threaded builds, each
377      * thread will have its own instance</li>
378      * <li><code>reuseSame</code>: the same Javacc class will be used for each compilation even for multi-threaded build
379      * </li>
380      * <li><code>alwaysNew</code>: a new Javacc class will be created for each compilation</li>
381      * </ul>
382      * Note this parameter value depends on the os/jdk you are using, but the default value should work on most of env.
383      *
384      * @since 2.5
385      */
386     @Parameter( defaultValue = "${reuseCreated}", property = "maven.compiler.compilerReuseStrategy" )
387     private String compilerReuseStrategy = "reuseCreated";
388 
389     /**
390      * @since 2.5
391      */
392     @Parameter( defaultValue = "false", property = "maven.compiler.skipMultiThreadWarning" )
393     private boolean skipMultiThreadWarning;
394 
395     /**
396      * compiler can now use javax.tools if available in your current jdk, you can disable this feature
397      * using -Dmaven.compiler.forceJavacCompilerUse=true or in the plugin configuration
398      *
399      * @since 3.0
400      */
401     @Parameter( defaultValue = "false", property = "maven.compiler.forceJavacCompilerUse" )
402     private boolean forceJavacCompilerUse;
403 
404     /**
405      * @since 3.0 needed for storing the status for the incremental build support.
406      */
407     @Parameter( defaultValue = "${mojoExecution}", readonly = true, required = true )
408     private MojoExecution mojoExecution;
409 
410     /**
411      * file extensions to check timestamp for incremental build
412      * <b>default contains only <code>.class</code></b>
413      *
414      * @since 3.1
415      */
416     @Parameter
417     private List<String> fileExtensions;
418 
419     /**
420      * to enable/disable incrementation compilation feature
421      * @since 3.1
422      */
423     @Parameter( defaultValue = "true", property = "maven.compiler.useIncrementalCompilation" )
424     private boolean useIncrementalCompilation = true;
425 
426     /**
427      * Resolves the artifacts needed.
428      */
429     @Component
430     private RepositorySystem repositorySystem;
431 
432     /**
433      * Artifact handler manager.
434      */
435     @Component
436     private ArtifactHandlerManager artifactHandlerManager;
437 
438     /**
439      * Throws an exception on artifact resolution errors.
440      */
441     @Component
442     private ResolutionErrorHandler resolutionErrorHandler;
443 
444     protected abstract SourceInclusionScanner getSourceInclusionScanner( int staleMillis );
445 
446     protected abstract SourceInclusionScanner getSourceInclusionScanner( String inputFileEnding );
447 
448     protected abstract List<String> getClasspathElements();
449 
450     protected abstract List<String> getCompileSourceRoots();
451 
452     protected abstract File getOutputDirectory();
453 
454     protected abstract String getSource();
455 
456     protected abstract String getTarget();
457 
458     protected abstract String getCompilerArgument();
459 
460     protected abstract Map<String, String> getCompilerArguments();
461 
462     protected abstract File getGeneratedSourcesDirectory();
463 
464     @Override
465     public void execute()
466         throws MojoExecutionException, CompilationFailureException
467     {
468         // ----------------------------------------------------------------------
469         // Look up the compiler. This is done before other code than can
470         // cause the mojo to return before the lookup is done possibly resulting
471         // in misconfigured POMs still building.
472         // ----------------------------------------------------------------------
473 
474         Compiler compiler;
475 
476         getLog().debug( "Using compiler '" + compilerId + "'." );
477 
478         try
479         {
480             compiler = compilerManager.getCompiler( compilerId );
481         }
482         catch ( NoSuchCompilerException e )
483         {
484             throw new MojoExecutionException( "No such compiler '" + e.getCompilerId() + "'." );
485         }
486 
487         //-----------toolchains start here ----------------------------------
488         //use the compilerId as identifier for toolchains as well.
489         Toolchain tc = getToolchain();
490         if ( tc != null )
491         {
492             getLog().info( "Toolchain in maven-compiler-plugin: " + tc );
493             if ( executable != null )
494             {
495                 getLog().warn( "Toolchains are ignored, 'executable' parameter is set to " + executable );
496             }
497             else
498             {
499                 fork = true;
500                 //TODO somehow shaky dependency between compilerId and tool executable.
501                 executable = tc.findTool( compilerId );
502             }
503         }
504         // ----------------------------------------------------------------------
505         //
506         // ----------------------------------------------------------------------
507 
508         List<String> compileSourceRoots = removeEmptyCompileSourceRoots( getCompileSourceRoots() );
509 
510         if ( compileSourceRoots.isEmpty() )
511         {
512             getLog().info( "No sources to compile" );
513 
514             return;
515         }
516 
517         if ( getLog().isDebugEnabled() )
518         {
519             getLog().debug( "Source directories: " + compileSourceRoots.toString().replace( ',', '\n' ) );
520             getLog().debug( "Classpath: " + getClasspathElements().toString().replace( ',', '\n' ) );
521             getLog().debug( "Output directory: " + getOutputDirectory() );
522         }
523 
524         // ----------------------------------------------------------------------
525         // Create the compiler configuration
526         // ----------------------------------------------------------------------
527 
528         CompilerConfiguration compilerConfiguration = new CompilerConfiguration();
529 
530         compilerConfiguration.setOutputLocation( getOutputDirectory().getAbsolutePath() );
531 
532         compilerConfiguration.setClasspathEntries( getClasspathElements() );
533 
534         compilerConfiguration.setOptimize( optimize );
535 
536         compilerConfiguration.setDebug( debug );
537 
538         if ( debug && StringUtils.isNotEmpty( debuglevel ) )
539         {
540             String[] split = StringUtils.split( debuglevel, "," );
541             for ( String aSplit : split )
542             {
543                 if ( !( aSplit.equalsIgnoreCase( "none" ) || aSplit.equalsIgnoreCase( "lines" )
544                     || aSplit.equalsIgnoreCase( "vars" ) || aSplit.equalsIgnoreCase( "source" ) ) )
545                 {
546                     throw new IllegalArgumentException( "The specified debug level: '" + aSplit + "' is unsupported. "
547                         + "Legal values are 'none', 'lines', 'vars', and 'source'." );
548                 }
549             }
550             compilerConfiguration.setDebugLevel( debuglevel );
551         }
552 
553         compilerConfiguration.setVerbose( verbose );
554 
555         compilerConfiguration.setShowWarnings( showWarnings );
556 
557         compilerConfiguration.setShowDeprecation( showDeprecation );
558 
559         compilerConfiguration.setSourceVersion( getSource() );
560 
561         compilerConfiguration.setTargetVersion( getTarget() );
562 
563         compilerConfiguration.setProc( proc );
564 
565         File generatedSourcesDirectory = getGeneratedSourcesDirectory();
566         compilerConfiguration.setGeneratedSourcesDirectory( generatedSourcesDirectory );
567 
568         if ( generatedSourcesDirectory != null )
569         {
570             String generatedSourcesPath = generatedSourcesDirectory.getAbsolutePath();
571 
572             compileSourceRoots.add( generatedSourcesPath );
573 
574             if ( isTestCompile() )
575             {
576                 getLog().debug( "Adding " + generatedSourcesPath + " to test-compile source roots:\n  "
577                                     + StringUtils.join( project.getTestCompileSourceRoots()
578                                                                .iterator(), "\n  " ) );
579 
580                 project.addTestCompileSourceRoot( generatedSourcesPath );
581 
582                 getLog().debug( "New test-compile source roots:\n  "
583                                     + StringUtils.join( project.getTestCompileSourceRoots()
584                                                                .iterator(), "\n  " ) );
585             }
586             else
587             {
588                 getLog().debug( "Adding " + generatedSourcesPath + " to compile source roots:\n  "
589                                     + StringUtils.join( project.getCompileSourceRoots()
590                                                                .iterator(), "\n  " ) );
591 
592                 project.addCompileSourceRoot( generatedSourcesPath );
593 
594                 getLog().debug( "New compile source roots:\n  " + StringUtils.join( project.getCompileSourceRoots()
595                                                                                            .iterator(), "\n  " ) );
596             }
597         }
598 
599         compilerConfiguration.setSourceLocations( compileSourceRoots );
600 
601         compilerConfiguration.setAnnotationProcessors( annotationProcessors );
602 
603         compilerConfiguration.setProcessorPathEntries( resolveProcessorPathEntries() );
604 
605         compilerConfiguration.setSourceEncoding( encoding );
606 
607         Map<String, String> effectiveCompilerArguments = getCompilerArguments();
608 
609         String effectiveCompilerArgument = getCompilerArgument();
610 
611         if ( ( effectiveCompilerArguments != null ) || ( effectiveCompilerArgument != null )
612                         || ( compilerArgs != null ) )
613         {
614             LinkedHashMap<String, String> cplrArgsCopy = new LinkedHashMap<String, String>();
615             if ( effectiveCompilerArguments != null )
616             {
617                 for ( Map.Entry<String, String> me : effectiveCompilerArguments.entrySet() )
618                 {
619                     String key = me.getKey();
620                     String value = me.getValue();
621                     if ( !key.startsWith( "-" ) )
622                     {
623                         key = "-" + key;
624                     }
625 
626                     if ( key.startsWith( "-A" ) && StringUtils.isNotEmpty( value ) )
627                     {
628                         cplrArgsCopy.put( key + "=" + value, null );
629                     }
630                     else
631                     {
632                         cplrArgsCopy.put( key, value );
633                     }
634                 }
635             }
636             if ( !StringUtils.isEmpty( effectiveCompilerArgument ) )
637             {
638                 cplrArgsCopy.put( effectiveCompilerArgument, null );
639             }
640             if ( compilerArgs != null )
641             {
642                 for ( String arg : compilerArgs )
643                 {
644                     cplrArgsCopy.put( arg, null );
645                 }
646             }
647             compilerConfiguration.setCustomCompilerArguments( cplrArgsCopy );
648         }
649 
650         compilerConfiguration.setFork( fork );
651 
652         if ( fork )
653         {
654             if ( !StringUtils.isEmpty( meminitial ) )
655             {
656                 String value = getMemoryValue( meminitial );
657 
658                 if ( value != null )
659                 {
660                     compilerConfiguration.setMeminitial( value );
661                 }
662                 else
663                 {
664                     getLog().info( "Invalid value for meminitial '" + meminitial + "'. Ignoring this option." );
665                 }
666             }
667 
668             if ( !StringUtils.isEmpty( maxmem ) )
669             {
670                 String value = getMemoryValue( maxmem );
671 
672                 if ( value != null )
673                 {
674                     compilerConfiguration.setMaxmem( value );
675                 }
676                 else
677                 {
678                     getLog().info( "Invalid value for maxmem '" + maxmem + "'. Ignoring this option." );
679                 }
680             }
681         }
682 
683         compilerConfiguration.setExecutable( executable );
684 
685         compilerConfiguration.setWorkingDirectory( basedir );
686 
687         compilerConfiguration.setCompilerVersion( compilerVersion );
688 
689         compilerConfiguration.setBuildDirectory( buildDirectory );
690 
691         compilerConfiguration.setOutputFileName( outputFileName );
692 
693         if ( CompilerConfiguration.CompilerReuseStrategy.AlwaysNew.getStrategy().equals( this.compilerReuseStrategy ) )
694         {
695             compilerConfiguration.setCompilerReuseStrategy( CompilerConfiguration.CompilerReuseStrategy.AlwaysNew );
696         }
697         else if ( CompilerConfiguration.CompilerReuseStrategy.ReuseSame.getStrategy().equals(
698             this.compilerReuseStrategy ) )
699         {
700             if ( getRequestThreadCount() > 1 )
701             {
702                 if ( !skipMultiThreadWarning )
703                 {
704                     getLog().warn( "You are in a multi-thread build and compilerReuseStrategy is set to reuseSame."
705                                        + " This can cause issues in some environments (os/jdk)!"
706                                        + " Consider using reuseCreated strategy."
707                                        + System.getProperty( "line.separator" )
708                                        + "If your env is fine with reuseSame, you can skip this warning with the "
709                                        + "configuration field skipMultiThreadWarning "
710                                        + "or -Dmaven.compiler.skipMultiThreadWarning=true" );
711                 }
712             }
713             compilerConfiguration.setCompilerReuseStrategy( CompilerConfiguration.CompilerReuseStrategy.ReuseSame );
714         }
715         else
716         {
717 
718             compilerConfiguration.setCompilerReuseStrategy( CompilerConfiguration.CompilerReuseStrategy.ReuseCreated );
719         }
720 
721         getLog().debug( "CompilerReuseStrategy: " + compilerConfiguration.getCompilerReuseStrategy().getStrategy() );
722 
723         compilerConfiguration.setForceJavacCompilerUse( forceJavacCompilerUse );
724 
725         boolean canUpdateTarget;
726 
727         IncrementalBuildHelper incrementalBuildHelper = new IncrementalBuildHelper( mojoExecution, session );
728 
729         Set<File> sources;
730 
731         IncrementalBuildHelperRequest incrementalBuildHelperRequest = null;
732 
733         if ( useIncrementalCompilation )
734         {
735             getLog().debug( "useIncrementalCompilation enabled" );
736             try
737             {
738                 canUpdateTarget = compiler.canUpdateTarget( compilerConfiguration );
739 
740                 sources = getCompileSources( compiler, compilerConfiguration );
741 
742                 incrementalBuildHelperRequest = new IncrementalBuildHelperRequest().inputFiles( sources );
743 
744                 // CHECKSTYLE_OFF: LineLength
745                 if ( ( compiler.getCompilerOutputStyle().equals( CompilerOutputStyle.ONE_OUTPUT_FILE_FOR_ALL_INPUT_FILES ) && !canUpdateTarget )
746                     || isDependencyChanged()
747                     || isSourceChanged( compilerConfiguration, compiler )
748                     || incrementalBuildHelper.inputFileTreeChanged( incrementalBuildHelperRequest ) )
749                     // CHECKSTYLE_ON: LineLength
750                 {
751                     getLog().info( "Changes detected - recompiling the module!" );
752 
753                     compilerConfiguration.setSourceFiles( sources );
754                 }
755                 else
756                 {
757                     getLog().info( "Nothing to compile - all classes are up to date" );
758 
759                     return;
760                 }
761             }
762             catch ( CompilerException e )
763             {
764                 throw new MojoExecutionException( "Error while computing stale sources.", e );
765             }
766         }
767         else
768         {
769             getLog().debug( "useIncrementalCompilation disabled" );
770             Set<File> staleSources;
771             try
772             {
773                 staleSources =
774                     computeStaleSources( compilerConfiguration, compiler, getSourceInclusionScanner( staleMillis ) );
775 
776                 canUpdateTarget = compiler.canUpdateTarget( compilerConfiguration );
777 
778                 if ( compiler.getCompilerOutputStyle().equals( CompilerOutputStyle.ONE_OUTPUT_FILE_FOR_ALL_INPUT_FILES )
779                     && !canUpdateTarget )
780                 {
781                     getLog().info( "RESCANNING!" );
782                     // TODO: This second scan for source files is sub-optimal
783                     String inputFileEnding = compiler.getInputFileEnding( compilerConfiguration );
784 
785                     sources = computeStaleSources( compilerConfiguration, compiler,
786                                                              getSourceInclusionScanner( inputFileEnding ) );
787 
788                     compilerConfiguration.setSourceFiles( sources );
789                 }
790                 else
791                 {
792                     compilerConfiguration.setSourceFiles( staleSources );
793                 }
794             }
795             catch ( CompilerException e )
796             {
797                 throw new MojoExecutionException( "Error while computing stale sources.", e );
798             }
799 
800             if ( staleSources.isEmpty() )
801             {
802                 getLog().info( "Nothing to compile - all classes are up to date" );
803 
804                 return;
805             }
806         }
807         // ----------------------------------------------------------------------
808         // Dump configuration
809         // ----------------------------------------------------------------------
810 
811         if ( getLog().isDebugEnabled() )
812         {
813             getLog().debug( "Classpath:" );
814 
815             for ( String s : getClasspathElements() )
816             {
817                 getLog().debug( " " + s );
818             }
819 
820             getLog().debug( "Source roots:" );
821 
822             for ( String root : getCompileSourceRoots() )
823             {
824                 getLog().debug( " " + root );
825             }
826 
827             try
828             {
829                 if ( fork )
830                 {
831                     if ( compilerConfiguration.getExecutable() != null )
832                     {
833                         getLog().debug( "Excutable: " );
834                         getLog().debug( " " + compilerConfiguration.getExecutable() );
835                     }
836                 }
837 
838                 String[] cl = compiler.createCommandLine( compilerConfiguration );
839                 if ( cl != null && cl.length > 0 )
840                 {
841                     StringBuilder sb = new StringBuilder();
842                     sb.append( cl[0] );
843                     for ( int i = 1; i < cl.length; i++ )
844                     {
845                         sb.append( " " );
846                         sb.append( cl[i] );
847                     }
848                     getLog().debug( "Command line options:" );
849                     getLog().debug( sb );
850                 }
851             }
852             catch ( CompilerException ce )
853             {
854                 getLog().debug( ce );
855             }
856         }
857 
858         // ----------------------------------------------------------------------
859         // Compile!
860         // ----------------------------------------------------------------------
861 
862         if ( StringUtils.isEmpty( compilerConfiguration.getSourceEncoding() ) )
863         {
864             getLog().warn( "File encoding has not been set, using platform encoding " + ReaderFactory.FILE_ENCODING
865                                + ", i.e. build is platform dependent!" );
866         }
867 
868         CompilerResult compilerResult;
869 
870 
871         if ( useIncrementalCompilation )
872         {
873             incrementalBuildHelperRequest.outputDirectory( getOutputDirectory() );
874 
875             incrementalBuildHelper.beforeRebuildExecution( incrementalBuildHelperRequest );
876 
877             getLog().debug( "incrementalBuildHelper#beforeRebuildExecution" );
878         }
879 
880         try
881         {
882             try
883             {
884                 compilerResult = compiler.performCompile( compilerConfiguration );
885             }
886             catch ( CompilerNotImplementedException cnie )
887             {
888                 List<CompilerError> messages = compiler.compile( compilerConfiguration );
889                 compilerResult = convertToCompilerResult( messages );
890             }
891         }
892         catch ( Exception e )
893         {
894             // TODO: don't catch Exception
895             throw new MojoExecutionException( "Fatal error compiling", e );
896         }
897 
898         if ( useIncrementalCompilation )
899         {
900             if ( incrementalBuildHelperRequest.getOutputDirectory().exists() )
901             {
902                 getLog().debug( "incrementalBuildHelper#afterRebuildExecution" );
903                 // now scan the same directory again and create a diff
904                 incrementalBuildHelper.afterRebuildExecution( incrementalBuildHelperRequest );
905             }
906             else
907             {
908                 getLog().debug(
909                     "skip incrementalBuildHelper#afterRebuildExecution as the output directory doesn't exist" );
910             }
911         }
912 
913         List<CompilerMessage> warnings = new ArrayList<CompilerMessage>();
914         List<CompilerMessage> errors = new ArrayList<CompilerMessage>();
915         List<CompilerMessage> others = new ArrayList<CompilerMessage>();
916         for ( CompilerMessage message : compilerResult.getCompilerMessages() )
917         {
918             if ( message.getKind() == CompilerMessage.Kind.ERROR )
919             {
920                 errors.add( message );
921             }
922             else if ( message.getKind() == CompilerMessage.Kind.WARNING
923                 || message.getKind() == CompilerMessage.Kind.MANDATORY_WARNING )
924             {
925                 warnings.add( message );
926             }
927             else
928             {
929                 others.add( message );
930             }
931         }
932 
933         if ( failOnError && !compilerResult.isSuccess() )
934         {
935             for ( CompilerMessage message : others )
936             {
937                 assert message.getKind() != CompilerMessage.Kind.ERROR
938                     && message.getKind() != CompilerMessage.Kind.WARNING
939                     && message.getKind() != CompilerMessage.Kind.MANDATORY_WARNING;
940                 getLog().info( message.toString() );
941             }
942             if ( !warnings.isEmpty() )
943             {
944                 getLog().info( "-------------------------------------------------------------" );
945                 getLog().warn( "COMPILATION WARNING : " );
946                 getLog().info( "-------------------------------------------------------------" );
947                 for ( CompilerMessage warning : warnings )
948                 {
949                     getLog().warn( warning.toString() );
950                 }
951                 getLog().info( warnings.size() + ( ( warnings.size() > 1 ) ? " warnings " : " warning" ) );
952                 getLog().info( "-------------------------------------------------------------" );
953             }
954 
955             if ( !errors.isEmpty() )
956             {
957                 getLog().info( "-------------------------------------------------------------" );
958                 getLog().error( "COMPILATION ERROR : " );
959                 getLog().info( "-------------------------------------------------------------" );
960                 for ( CompilerMessage error : errors )
961                 {
962                     getLog().error( error.toString() );
963                 }
964                 getLog().info( errors.size() + ( ( errors.size() > 1 ) ? " errors " : " error" ) );
965                 getLog().info( "-------------------------------------------------------------" );
966             }
967 
968             if ( !errors.isEmpty() )
969             {
970                 throw new CompilationFailureException( errors );
971             }
972             else
973             {
974                 throw new CompilationFailureException( warnings );
975             }
976         }
977         else
978         {
979             for ( CompilerMessage message : compilerResult.getCompilerMessages() )
980             {
981                 switch ( message.getKind() )
982                 {
983                     case NOTE:
984                     case OTHER:
985                         getLog().info( message.toString() );
986                         break;
987 
988                     case ERROR:
989                         getLog().error( message.toString() );
990                         break;
991 
992                     case MANDATORY_WARNING:
993                     case WARNING:
994                     default:
995                         getLog().warn( message.toString() );
996                         break;
997                 }
998             }
999         }
1000     }
1001 
1002     protected boolean isTestCompile()
1003     {
1004         return false;
1005     }
1006 
1007     protected CompilerResult convertToCompilerResult( List<CompilerError> compilerErrors )
1008     {
1009         if ( compilerErrors == null )
1010         {
1011             return new CompilerResult();
1012         }
1013         List<CompilerMessage> messages = new ArrayList<CompilerMessage>( compilerErrors.size() );
1014         boolean success = true;
1015         for ( CompilerError compilerError : compilerErrors )
1016         {
1017             messages.add(
1018                 new CompilerMessage( compilerError.getFile(), compilerError.getKind(), compilerError.getStartLine(),
1019                                      compilerError.getStartColumn(), compilerError.getEndLine(),
1020                                      compilerError.getEndColumn(), compilerError.getMessage() ) );
1021             if ( compilerError.isError() )
1022             {
1023                 success = false;
1024             }
1025         }
1026 
1027         return new CompilerResult( success, messages );
1028     }
1029 
1030     /**
1031      * @return all source files for the compiler
1032      */
1033     private Set<File> getCompileSources( Compiler compiler, CompilerConfiguration compilerConfiguration )
1034         throws MojoExecutionException, CompilerException
1035     {
1036         String inputFileEnding = compiler.getInputFileEnding( compilerConfiguration );
1037         if ( StringUtils.isEmpty( inputFileEnding ) )
1038         {
1039             // see MCOMPILER-199 GroovyEclipseCompiler doesn't set inputFileEnding
1040             // so we can presume it's all files from the source directory
1041             inputFileEnding = ".*";
1042         }
1043         SourceInclusionScanner scanner = getSourceInclusionScanner( inputFileEnding );
1044 
1045         SourceMapping mapping = getSourceMapping( compilerConfiguration, compiler );
1046 
1047         scanner.addSourceMapping( mapping );
1048 
1049         Set<File> compileSources = new HashSet<File>();
1050 
1051         for ( String sourceRoot : getCompileSourceRoots() )
1052         {
1053             File rootFile = new File( sourceRoot );
1054 
1055             if ( !rootFile.isDirectory() )
1056             {
1057                 continue;
1058             }
1059 
1060             try
1061             {
1062                 compileSources.addAll( scanner.getIncludedSources( rootFile, null ) );
1063             }
1064             catch ( InclusionScanException e )
1065             {
1066                 throw new MojoExecutionException(
1067                     "Error scanning source root: \'" + sourceRoot + "\' for stale files to recompile.", e );
1068             }
1069         }
1070 
1071         return compileSources;
1072     }
1073 
1074     /**
1075      * @param compilerConfiguration
1076      * @param compiler
1077      * @return <code>true</code> if at least a single source file is newer than it's class file
1078      */
1079     private boolean isSourceChanged( CompilerConfiguration compilerConfiguration, Compiler compiler )
1080         throws CompilerException, MojoExecutionException
1081     {
1082         Set<File> staleSources =
1083             computeStaleSources( compilerConfiguration, compiler, getSourceInclusionScanner( staleMillis ) );
1084 
1085         if ( getLog().isDebugEnabled() )
1086         {
1087             for ( File f : staleSources )
1088             {
1089                 getLog().debug( "Stale source detected: " + f.getAbsolutePath() );
1090             }
1091         }
1092         return staleSources != null && staleSources.size() > 0;
1093     }
1094 
1095 
1096     /**
1097      * try to get thread count if a Maven 3 build, using reflection as the plugin must not be maven3 api dependent
1098      *
1099      * @return number of thread for this build or 1 if not multi-thread build
1100      */
1101     protected int getRequestThreadCount()
1102     {
1103         try
1104         {
1105             Method getRequestMethod = session.getClass().getMethod( "getRequest" );
1106             Object mavenExecutionRequest = getRequestMethod.invoke( this.session );
1107             Method getThreadCountMethod = mavenExecutionRequest.getClass().getMethod( "getThreadCount" );
1108             String threadCount = (String) getThreadCountMethod.invoke( mavenExecutionRequest );
1109             return Integer.valueOf( threadCount );
1110         }
1111         catch ( Exception e )
1112         {
1113             getLog().debug( "unable to get threadCount for the current build: " + e.getMessage() );
1114         }
1115         return 1;
1116     }
1117 
1118     protected Date getBuildStartTime()
1119     {
1120         Date buildStartTime = null;
1121         try
1122         {
1123             Method getRequestMethod = session.getClass().getMethod( "getRequest" );
1124             Object mavenExecutionRequest = getRequestMethod.invoke( session );
1125             Method getStartTimeMethod = mavenExecutionRequest.getClass().getMethod( "getStartTime" );
1126             buildStartTime = (Date) getStartTimeMethod.invoke( mavenExecutionRequest );
1127         }
1128         catch ( Exception e )
1129         {
1130             getLog().debug( "unable to get start time for the current build: " + e.getMessage() );
1131         }
1132 
1133         if ( buildStartTime == null )
1134         {
1135             return new Date();
1136         }
1137 
1138         return buildStartTime;
1139     }
1140 
1141 
1142     private String getMemoryValue( String setting )
1143     {
1144         String value = null;
1145 
1146         // Allow '128' or '128m'
1147         if ( isDigits( setting ) )
1148         {
1149             value = setting + "m";
1150         }
1151         else if ( ( isDigits( setting.substring( 0, setting.length() - 1 ) ) )
1152             && ( setting.toLowerCase().endsWith( "m" ) ) )
1153         {
1154             value = setting;
1155         }
1156         return value;
1157     }
1158 
1159     //TODO remove the part with ToolchainManager lookup once we depend on
1160     //3.0.9 (have it as prerequisite). Define as regular component field then.
1161     private Toolchain getToolchain()
1162     {
1163         Toolchain tc = null;
1164         if ( toolchainManager != null )
1165         {
1166             tc = toolchainManager.getToolchainFromBuildContext( "jdk", session );
1167         }
1168         return tc;
1169     }
1170 
1171     private boolean isDigits( String string )
1172     {
1173         for ( int i = 0; i < string.length(); i++ )
1174         {
1175             if ( !Character.isDigit( string.charAt( i ) ) )
1176             {
1177                 return false;
1178             }
1179         }
1180         return true;
1181     }
1182 
1183     private Set<File> computeStaleSources( CompilerConfiguration compilerConfiguration, Compiler compiler,
1184                                            SourceInclusionScanner scanner )
1185         throws MojoExecutionException, CompilerException
1186     {
1187         SourceMapping mapping = getSourceMapping( compilerConfiguration, compiler );
1188 
1189         File outputDirectory;
1190         CompilerOutputStyle outputStyle = compiler.getCompilerOutputStyle();
1191         if ( outputStyle == CompilerOutputStyle.ONE_OUTPUT_FILE_FOR_ALL_INPUT_FILES )
1192         {
1193             outputDirectory = buildDirectory;
1194         }
1195         else
1196         {
1197             outputDirectory = getOutputDirectory();
1198         }
1199 
1200         scanner.addSourceMapping( mapping );
1201 
1202         Set<File> staleSources = new HashSet<File>();
1203 
1204         for ( String sourceRoot : getCompileSourceRoots() )
1205         {
1206             File rootFile = new File( sourceRoot );
1207 
1208             if ( !rootFile.isDirectory() )
1209             {
1210                 continue;
1211             }
1212 
1213             try
1214             {
1215                 staleSources.addAll( scanner.getIncludedSources( rootFile, outputDirectory ) );
1216             }
1217             catch ( InclusionScanException e )
1218             {
1219                 throw new MojoExecutionException(
1220                     "Error scanning source root: \'" + sourceRoot + "\' for stale files to recompile.", e );
1221             }
1222         }
1223 
1224         return staleSources;
1225     }
1226 
1227     private SourceMapping getSourceMapping( CompilerConfiguration compilerConfiguration, Compiler compiler )
1228         throws CompilerException, MojoExecutionException
1229     {
1230         CompilerOutputStyle outputStyle = compiler.getCompilerOutputStyle();
1231 
1232         SourceMapping mapping;
1233         if ( outputStyle == CompilerOutputStyle.ONE_OUTPUT_FILE_PER_INPUT_FILE )
1234         {
1235             mapping = new SuffixMapping( compiler.getInputFileEnding( compilerConfiguration ),
1236                                          compiler.getOutputFileEnding( compilerConfiguration ) );
1237         }
1238         else if ( outputStyle == CompilerOutputStyle.ONE_OUTPUT_FILE_FOR_ALL_INPUT_FILES )
1239         {
1240             mapping = new SingleTargetSourceMapping( compiler.getInputFileEnding( compilerConfiguration ),
1241                                                      compiler.getOutputFile( compilerConfiguration ) );
1242 
1243         }
1244         else
1245         {
1246             throw new MojoExecutionException( "Unknown compiler output style: '" + outputStyle + "'." );
1247         }
1248         return mapping;
1249     }
1250 
1251     /**
1252      * @todo also in ant plugin. This should be resolved at some point so that it does not need to
1253      * be calculated continuously - or should the plugins accept empty source roots as is?
1254      */
1255     private static List<String> removeEmptyCompileSourceRoots( List<String> compileSourceRootsList )
1256     {
1257         List<String> newCompileSourceRootsList = new ArrayList<String>();
1258         if ( compileSourceRootsList != null )
1259         {
1260             // copy as I may be modifying it
1261             for ( String srcDir : compileSourceRootsList )
1262             {
1263                 if ( !newCompileSourceRootsList.contains( srcDir ) && new File( srcDir ).exists() )
1264                 {
1265                     newCompileSourceRootsList.add( srcDir );
1266                 }
1267             }
1268         }
1269         return newCompileSourceRootsList;
1270     }
1271 
1272     /**
1273      * We just compare the timestamps of all local dependency files (inter-module dependency classpath)
1274      * and the own generated classes
1275      * and if we got a file which is >= the buid-started timestamp, then we catched a file which got
1276      * changed during this build.
1277      *
1278      * @return <code>true</code> if at least one single dependency has changed.
1279      */
1280     protected boolean isDependencyChanged()
1281     {
1282         if ( session == null )
1283         {
1284             // we just cannot determine it, so don't do anything beside logging
1285             getLog().info( "Cannot determine build start date, skipping incremental build detection." );
1286             return false;
1287         }
1288 
1289         if ( fileExtensions == null || fileExtensions.isEmpty() )
1290         {
1291             fileExtensions = new ArrayList<String>();
1292             fileExtensions.add( ".class" );
1293         }
1294 
1295         Date buildStartTime = getBuildStartTime();
1296 
1297         for ( String classPathElement : getClasspathElements() )
1298         {
1299             // ProjectArtifacts are artifacts which are available in the local project
1300             // that's the only ones we are interested in now.
1301             File artifactPath = new File( classPathElement );
1302             if ( artifactPath.isDirectory() )
1303             {
1304                 if ( hasNewFile( artifactPath, buildStartTime ) )
1305                 {
1306                     getLog().debug( "New dependency detected: " + artifactPath.getAbsolutePath() );
1307                     return true;
1308                 }
1309             }
1310         }
1311 
1312         // obviously there was no new file detected.
1313         return false;
1314     }
1315 
1316     /**
1317      * @param classPathEntry entry to check
1318      * @param buildStartTime time build start
1319      * @return if any changes occurred
1320      */
1321     private boolean hasNewFile( File classPathEntry, Date buildStartTime )
1322     {
1323         if ( !classPathEntry.exists() )
1324         {
1325             return false;
1326         }
1327 
1328         if ( classPathEntry.isFile() )
1329         {
1330             return classPathEntry.lastModified() >= buildStartTime.getTime()
1331                 && fileExtensions.contains( FileUtils.getExtension( classPathEntry.getName() ) );
1332         }
1333 
1334         File[] children = classPathEntry.listFiles();
1335 
1336         for ( File child : children )
1337         {
1338             if ( hasNewFile( child, buildStartTime ) )
1339             {
1340                 return true;
1341             }
1342         }
1343 
1344         return false;
1345     }
1346 
1347     private List<String> resolveProcessorPathEntries()
1348         throws MojoExecutionException
1349     {
1350         if ( annotationProcessorPaths == null || annotationProcessorPaths.isEmpty() )
1351         {
1352             return null;
1353         }
1354 
1355         try
1356         {
1357             Set<Artifact> requiredArtifacts = new HashSet<Artifact>();
1358 
1359             for ( DependencyCoordinate coord : annotationProcessorPaths )
1360             {
1361                 ArtifactHandler handler = artifactHandlerManager.getArtifactHandler( coord.getType() );
1362 
1363                 Artifact artifact = new DefaultArtifact(
1364                      coord.getGroupId(),
1365                      coord.getArtifactId(),
1366                      VersionRange.createFromVersionSpec( coord.getVersion() ),
1367                      Artifact.SCOPE_RUNTIME,
1368                      coord.getType(),
1369                      coord.getClassifier(),
1370                      handler,
1371                      false );
1372 
1373                 requiredArtifacts.add( artifact );
1374             }
1375 
1376             ArtifactResolutionRequest request = new ArtifactResolutionRequest()
1377                             .setArtifact( project.getArtifact() )
1378                             .setResolveRoot( false )
1379                             .setResolveTransitively( true )
1380                             .setArtifactDependencies( requiredArtifacts )
1381                             .setLocalRepository( session.getLocalRepository() )
1382                             .setRemoteRepositories( project.getRemoteArtifactRepositories() );
1383 
1384             ArtifactResolutionResult resolutionResult = repositorySystem.resolve( request );
1385 
1386             resolutionErrorHandler.throwErrors( request, resolutionResult );
1387 
1388             List<String> classpathElements = new ArrayList<String>( resolutionResult.getArtifacts().size() );
1389 
1390             for ( Object resolved : resolutionResult.getArtifacts() )
1391             {
1392                 classpathElements.add( ( (Artifact) resolved ).getFile().getAbsolutePath() );
1393             }
1394 
1395             return classpathElements;
1396         }
1397         catch ( Exception e )
1398         {
1399             throw new MojoExecutionException( "Resolution of annotationProcessorPath dependencies failed: "
1400                 + e.getLocalizedMessage(), e );
1401         }
1402     }
1403 }