1   
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  package org.apache.maven.plugin.compiler;
20  
21  import java.io.File;
22  import java.io.IOException;
23  import java.io.InputStream;
24  import java.nio.charset.Charset;
25  import java.nio.file.Files;
26  import java.nio.file.Path;
27  import java.nio.file.Paths;
28  import java.time.Instant;
29  import java.time.temporal.ChronoUnit;
30  import java.util.ArrayList;
31  import java.util.Arrays;
32  import java.util.Collections;
33  import java.util.Comparator;
34  import java.util.Date;
35  import java.util.HashSet;
36  import java.util.Iterator;
37  import java.util.LinkedHashSet;
38  import java.util.List;
39  import java.util.Map;
40  import java.util.Objects;
41  import java.util.Optional;
42  import java.util.Properties;
43  import java.util.Set;
44  import java.util.stream.Collectors;
45  import java.util.stream.Stream;
46  
47  import org.apache.maven.RepositoryUtils;
48  import org.apache.maven.artifact.handler.ArtifactHandler;
49  import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
50  import org.apache.maven.execution.MavenExecutionRequest;
51  import org.apache.maven.execution.MavenSession;
52  import org.apache.maven.model.Dependency;
53  import org.apache.maven.model.DependencyManagement;
54  import org.apache.maven.plugin.AbstractMojo;
55  import org.apache.maven.plugin.MojoExecution;
56  import org.apache.maven.plugin.MojoExecutionException;
57  import org.apache.maven.plugins.annotations.Component;
58  import org.apache.maven.plugins.annotations.Parameter;
59  import org.apache.maven.project.MavenProject;
60  import org.apache.maven.shared.incremental.IncrementalBuildHelper;
61  import org.apache.maven.shared.incremental.IncrementalBuildHelperRequest;
62  import org.apache.maven.shared.utils.StringUtils;
63  import org.apache.maven.shared.utils.logging.MessageBuilder;
64  import org.apache.maven.shared.utils.logging.MessageUtils;
65  import org.apache.maven.toolchain.Toolchain;
66  import org.apache.maven.toolchain.ToolchainManager;
67  import org.codehaus.plexus.compiler.Compiler;
68  import org.codehaus.plexus.compiler.CompilerConfiguration;
69  import org.codehaus.plexus.compiler.CompilerException;
70  import org.codehaus.plexus.compiler.CompilerMessage;
71  import org.codehaus.plexus.compiler.CompilerOutputStyle;
72  import org.codehaus.plexus.compiler.CompilerResult;
73  import org.codehaus.plexus.compiler.manager.CompilerManager;
74  import org.codehaus.plexus.compiler.manager.NoSuchCompilerException;
75  import org.codehaus.plexus.compiler.util.scan.InclusionScanException;
76  import org.codehaus.plexus.compiler.util.scan.SourceInclusionScanner;
77  import org.codehaus.plexus.compiler.util.scan.mapping.SingleTargetSourceMapping;
78  import org.codehaus.plexus.compiler.util.scan.mapping.SourceMapping;
79  import org.codehaus.plexus.compiler.util.scan.mapping.SuffixMapping;
80  import org.codehaus.plexus.languages.java.jpms.JavaModuleDescriptor;
81  import org.codehaus.plexus.languages.java.version.JavaVersion;
82  import org.codehaus.plexus.util.FileUtils;
83  import org.eclipse.aether.RepositorySystem;
84  import org.eclipse.aether.artifact.Artifact;
85  import org.eclipse.aether.artifact.ArtifactTypeRegistry;
86  import org.eclipse.aether.artifact.DefaultArtifact;
87  import org.eclipse.aether.collection.CollectRequest;
88  import org.eclipse.aether.graph.Exclusion;
89  import org.eclipse.aether.resolution.DependencyRequest;
90  import org.eclipse.aether.resolution.DependencyResult;
91  import org.eclipse.aether.util.artifact.JavaScopes;
92  import org.objectweb.asm.ClassWriter;
93  import org.objectweb.asm.Opcodes;
94  
95  
96  
97  
98  
99  
100 
101 
102 
103 
104 
105 public abstract class AbstractCompilerMojo extends AbstractMojo {
106     protected static final String PS = System.getProperty("path.separator");
107 
108     private static final String INPUT_FILES_LST_FILENAME = "inputFiles.lst";
109 
110     static final String DEFAULT_SOURCE = "1.8";
111 
112     static final String DEFAULT_TARGET = "1.8";
113 
114     
115     
116     
117 
118     
119 
120 
121 
122 
123     @Parameter(property = "maven.compiler.failOnError", defaultValue = "true")
124     private boolean failOnError = true;
125 
126     
127 
128 
129 
130 
131     @Parameter(property = "maven.compiler.failOnWarning", defaultValue = "false")
132     private boolean failOnWarning;
133 
134     
135 
136 
137 
138 
139     @Parameter(property = "maven.compiler.debug", defaultValue = "true")
140     private boolean debug = true;
141 
142     
143 
144 
145 
146 
147     @Parameter(property = "maven.compiler.parameters", defaultValue = "false")
148     private boolean parameters;
149 
150     
151 
152 
153 
154 
155     @Parameter(property = "maven.compiler.enablePreview", defaultValue = "false")
156     private boolean enablePreview;
157 
158     
159 
160 
161 
162 
163     @Parameter(property = "maven.compiler.verbose", defaultValue = "false")
164     private boolean verbose;
165 
166     
167 
168 
169     @Parameter(property = "maven.compiler.showDeprecation", defaultValue = "false")
170     private boolean showDeprecation;
171 
172     
173 
174 
175 
176     @Deprecated
177     @Parameter(property = "maven.compiler.optimize", defaultValue = "false")
178     private boolean optimize;
179 
180     
181 
182 
183     @Parameter(property = "maven.compiler.showWarnings", defaultValue = "true")
184     private boolean showWarnings;
185 
186     
187 
188 
189 
190 
191 
192 
193 
194 
195     @Parameter(property = "maven.compiler.source", defaultValue = DEFAULT_SOURCE)
196     protected String source;
197 
198     
199 
200 
201 
202 
203 
204 
205 
206 
207 
208     @Parameter(property = "maven.compiler.target", defaultValue = DEFAULT_TARGET)
209     protected String target;
210 
211     
212 
213 
214 
215 
216 
217     @Parameter(property = "maven.compiler.release")
218     protected String release;
219 
220     
221 
222 
223 
224 
225 
226     @Parameter(property = "encoding", defaultValue = "${project.build.sourceEncoding}")
227     private String encoding;
228 
229     
230 
231 
232 
233     @Parameter(property = "lastModGranularityMs", defaultValue = "0")
234     private int staleMillis;
235 
236     
237 
238 
239 
240     @Parameter(property = "maven.compiler.compilerId", defaultValue = "javac")
241     private String compilerId;
242 
243     
244 
245 
246 
247 
248     @Deprecated
249     @Parameter(property = "maven.compiler.compilerVersion")
250     private String compilerVersion;
251 
252     
253 
254 
255 
256     @Parameter(property = "maven.compiler.fork", defaultValue = "false")
257     private boolean fork;
258 
259     
260 
261 
262 
263 
264 
265     @Parameter(property = "maven.compiler.meminitial")
266     private String meminitial;
267 
268     
269 
270 
271 
272 
273 
274     @Parameter(property = "maven.compiler.maxmem")
275     private String maxmem;
276 
277     
278 
279 
280     @Parameter(property = "maven.compiler.executable")
281     private String executable;
282 
283     
284 
285 
286 
287 
288 
289 
290 
291 
292 
293 
294 
295 
296 
297 
298 
299 
300 
301     @Parameter(property = "maven.compiler.proc")
302     private String proc;
303 
304     
305 
306 
307 
308 
309 
310 
311 
312 
313 
314     @Parameter
315     private String[] annotationProcessors;
316 
317     
318 
319 
320 
321 
322 
323 
324 
325 
326 
327 
328 
329 
330 
331 
332 
333 
334 
335 
336 
337 
338 
339 
340 
341 
342 
343 
344 
345 
346 
347 
348 
349 
350 
351 
352 
353 
354 
355     @Parameter
356     private List<DependencyCoordinate> annotationProcessorPaths;
357 
358     
359 
360 
361 
362 
363 
364 
365 
366 
367 
368 
369 
370 
371     @Parameter(defaultValue = "false")
372     private boolean annotationProcessorPathsUseDepMgmt;
373 
374     
375 
376 
377 
378 
379 
380 
381 
382 
383 
384 
385 
386 
387 
388 
389 
390 
391 
392 
393 
394 
395 
396 
397 
398 
399 
400     @Parameter
401     @Deprecated
402     protected Map<String, String> compilerArguments;
403 
404     
405 
406 
407 
408 
409 
410 
411 
412 
413 
414 
415 
416 
417 
418 
419 
420 
421 
422 
423 
424     @Parameter
425     protected List<String> compilerArgs;
426 
427     
428 
429 
430 
431 
432 
433 
434 
435 
436 
437 
438 
439 
440     @Parameter
441     protected String compilerArgument;
442 
443     
444 
445 
446 
447 
448 
449     @Parameter
450     private String outputFileName;
451 
452     
453 
454 
455 
456 
457 
458 
459 
460 
461     @Parameter(property = "maven.compiler.debuglevel")
462     private String debuglevel;
463 
464     
465 
466 
467 
468 
469 
470     @Parameter(property = "maven.compiler.implicit")
471     private String implicit;
472 
473     
474 
475 
476     @Component
477     private ToolchainManager toolchainManager;
478 
479     
480 
481 
482 
483 
484 
485 
486 
487 
488 
489 
490 
491 
492 
493 
494 
495 
496 
497 
498 
499 
500 
501 
502 
503 
504 
505 
506 
507 
508     @Parameter
509     private Map<String, String> jdkToolchain;
510 
511     
512     
513     
514 
515     
516 
517 
518     @Parameter(defaultValue = "${basedir}", required = true, readonly = true)
519     private File basedir;
520 
521     
522 
523 
524     @Parameter(defaultValue = "${project.build.directory}", required = true, readonly = true)
525     private File buildDirectory;
526 
527     
528 
529 
530     @Component
531     private CompilerManager compilerManager;
532 
533     
534 
535 
536     @Parameter(defaultValue = "${session}", readonly = true, required = true)
537     private MavenSession session;
538 
539     
540 
541 
542 
543     @Parameter(defaultValue = "${project}", readonly = true, required = true)
544     private MavenProject project;
545 
546     
547 
548 
549 
550 
551 
552 
553 
554 
555 
556 
557 
558 
559     @Parameter(defaultValue = "${reuseCreated}", property = "maven.compiler.compilerReuseStrategy")
560     private String compilerReuseStrategy = "reuseCreated";
561 
562     
563 
564 
565     @Parameter(defaultValue = "false", property = "maven.compiler.skipMultiThreadWarning")
566     private boolean skipMultiThreadWarning;
567 
568     
569 
570 
571 
572 
573 
574     @Deprecated
575     @Parameter(defaultValue = "false", property = "maven.compiler.forceJavacCompilerUse")
576     private boolean forceJavacCompilerUse;
577 
578     
579 
580 
581 
582 
583 
584 
585 
586 
587 
588     @Parameter(defaultValue = "false", property = "maven.compiler.forceLegacyJavacApi")
589     private boolean forceLegacyJavacApi;
590 
591     
592 
593 
594     @Parameter(defaultValue = "${mojoExecution}", readonly = true, required = true)
595     private MojoExecution mojoExecution;
596 
597     
598 
599 
600 
601 
602     @Parameter(defaultValue = "class,jar")
603     private Set<String> fileExtensions;
604 
605     
606 
607 
608 
609 
610 
611 
612 
613 
614 
615 
616 
617 
618 
619 
620 
621     @Parameter(defaultValue = "true", property = "maven.compiler.useIncrementalCompilation")
622     private boolean useIncrementalCompilation = true;
623 
624     
625 
626 
627 
628 
629 
630 
631 
632 
633     @Parameter(defaultValue = "true", property = "maven.compiler.createMissingPackageInfoClass")
634     private boolean createMissingPackageInfoClass = true;
635 
636     @Parameter(defaultValue = "false", property = "maven.compiler.showCompilationChanges")
637     private boolean showCompilationChanges = false;
638 
639     
640 
641 
642 
643 
644 
645     @Parameter(defaultValue = "${project.build.outputTimestamp}")
646     private String outputTimestamp;
647 
648     
649 
650 
651     @Component
652     private RepositorySystem repositorySystem;
653 
654     
655 
656 
657     @Component
658     private ArtifactHandlerManager artifactHandlerManager;
659 
660     protected abstract SourceInclusionScanner getSourceInclusionScanner(int staleMillis);
661 
662     protected abstract SourceInclusionScanner getSourceInclusionScanner(String inputFileEnding);
663 
664     protected abstract List<String> getClasspathElements();
665 
666     protected abstract List<String> getModulepathElements();
667 
668     protected abstract Map<String, JavaModuleDescriptor> getPathElements();
669 
670     protected abstract List<String> getCompileSourceRoots();
671 
672     protected abstract void preparePaths(Set<File> sourceFiles);
673 
674     protected abstract File getOutputDirectory();
675 
676     protected abstract String getSource();
677 
678     protected abstract String getTarget();
679 
680     protected abstract String getRelease();
681 
682     protected abstract String getCompilerArgument();
683 
684     protected abstract Map<String, String> getCompilerArguments();
685 
686     protected abstract File getGeneratedSourcesDirectory();
687 
688     protected abstract String getDebugFileName();
689 
690     protected final MavenProject getProject() {
691         return project;
692     }
693 
694     protected final Optional<Path> getModuleDeclaration(final Set<File> sourceFiles) {
695         for (File sourceFile : sourceFiles) {
696             if ("module-info.java".equals(sourceFile.getName())) {
697                 return Optional.of(sourceFile.toPath());
698             }
699         }
700         return Optional.empty();
701     }
702 
703     private boolean targetOrReleaseSet;
704 
705     @Override
706     public void execute() throws MojoExecutionException, CompilationFailureException {
707         try {
708             executeReal();
709         } finally {
710             addGeneratedSourcesToProject();
711         }
712     }
713 
714     private void addGeneratedSourcesToProject() {
715         File generatedSourcesDirectory = getGeneratedSourcesDirectory();
716         if (generatedSourcesDirectory == null) {
717             return;
718         }
719 
720         String generatedSourcesPath = generatedSourcesDirectory.getAbsolutePath();
721 
722         if (isTestCompile()) {
723             getLog().debug("Adding " + generatedSourcesPath
724                     + " to the project test-compile source roots but NOT the actual test-compile source roots:\n  "
725                     + StringUtils.join(project.getTestCompileSourceRoots().iterator(), "\n  "));
726 
727             project.addTestCompileSourceRoot(generatedSourcesPath);
728         } else {
729             getLog().debug("Adding " + generatedSourcesPath
730                     + " to the project compile source roots but NOT the actual compile source roots:\n  "
731                     + StringUtils.join(project.getCompileSourceRoots().iterator(), "\n  "));
732 
733             project.addCompileSourceRoot(generatedSourcesPath);
734         }
735     }
736 
737     @SuppressWarnings("checkstyle:MethodLength")
738     private void executeReal() throws MojoExecutionException, CompilationFailureException {
739         
740         
741         
742         
743         
744 
745         Compiler compiler;
746 
747         getLog().debug("Using compiler '" + compilerId + "'.");
748 
749         try {
750             compiler = compilerManager.getCompiler(compilerId);
751         } catch (NoSuchCompilerException e) {
752             throw new MojoExecutionException("No such compiler '" + e.getCompilerId() + "'.", e);
753         }
754 
755         
756         
757         Toolchain tc = getToolchain();
758         if (tc != null) {
759             getLog().info("Toolchain in maven-compiler-plugin: " + tc);
760             if (executable != null) {
761                 getLog().warn("Toolchains are ignored, 'executable' parameter is set to " + executable);
762             } else {
763                 fork = true;
764                 
765                 executable = tc.findTool(compilerId);
766             }
767         }
768         
769         
770         
771 
772         List<String> compileSourceRoots = removeEmptyCompileSourceRoots(getCompileSourceRoots());
773 
774         if (compileSourceRoots.isEmpty()) {
775             getLog().info("No sources to compile");
776 
777             return;
778         }
779 
780         
781         if (!targetOrReleaseSet) {
782             MessageBuilder mb = MessageUtils.buffer()
783                     .a("No explicit value set for target or release! ")
784                     .a("To ensure the same result even after upgrading this plugin, please add ")
785                     .newline()
786                     .newline();
787 
788             writePlugin(mb);
789 
790             getLog().warn(mb.toString());
791         }
792 
793         
794         
795         
796 
797         CompilerConfiguration compilerConfiguration = new CompilerConfiguration();
798 
799         compilerConfiguration.setOutputLocation(getOutputDirectory().getAbsolutePath());
800 
801         compilerConfiguration.setOptimize(optimize);
802 
803         compilerConfiguration.setDebug(debug);
804 
805         compilerConfiguration.setDebugFileName(getDebugFileName());
806 
807         compilerConfiguration.setImplicitOption(implicit);
808 
809         if (debug && (debuglevel != null && !debuglevel.isEmpty())) {
810             String[] split = StringUtils.split(debuglevel, ",");
811             for (String aSplit : split) {
812                 if (!(aSplit.equalsIgnoreCase("none")
813                         || aSplit.equalsIgnoreCase("lines")
814                         || aSplit.equalsIgnoreCase("vars")
815                         || aSplit.equalsIgnoreCase("source"))) {
816                     throw new IllegalArgumentException("The specified debug level: '" + aSplit + "' is unsupported. "
817                             + "Legal values are 'none', 'lines', 'vars', and 'source'.");
818                 }
819             }
820             compilerConfiguration.setDebugLevel(debuglevel);
821         }
822 
823         compilerConfiguration.setParameters(parameters);
824 
825         compilerConfiguration.setEnablePreview(enablePreview);
826 
827         compilerConfiguration.setVerbose(verbose);
828 
829         compilerConfiguration.setShowWarnings(showWarnings);
830 
831         compilerConfiguration.setFailOnWarning(failOnWarning);
832 
833         if (failOnWarning && !showWarnings) {
834             getLog().warn("The property failOnWarning is set to true, but showWarnings is set to false.");
835             getLog().warn("With compiler's warnings silenced the failOnWarning has no effect.");
836         }
837 
838         compilerConfiguration.setShowDeprecation(showDeprecation);
839 
840         compilerConfiguration.setSourceVersion(getSource());
841 
842         compilerConfiguration.setTargetVersion(getTarget());
843 
844         compilerConfiguration.setReleaseVersion(getRelease());
845 
846         compilerConfiguration.setProc(proc);
847 
848         File generatedSourcesDirectory = getGeneratedSourcesDirectory();
849         compilerConfiguration.setGeneratedSourcesDirectory(
850                 generatedSourcesDirectory != null ? generatedSourcesDirectory.getAbsoluteFile() : null);
851 
852         if (generatedSourcesDirectory != null) {
853             if (!generatedSourcesDirectory.exists()) {
854                 generatedSourcesDirectory.mkdirs();
855             }
856         }
857 
858         compilerConfiguration.setSourceLocations(compileSourceRoots);
859 
860         compilerConfiguration.setAnnotationProcessors(annotationProcessors);
861 
862         compilerConfiguration.setProcessorPathEntries(resolveProcessorPathEntries());
863 
864         compilerConfiguration.setSourceEncoding(encoding);
865 
866         compilerConfiguration.setFork(fork);
867 
868         if (fork) {
869             if (!(meminitial == null || meminitial.isEmpty())) {
870                 String value = getMemoryValue(meminitial);
871 
872                 if (value != null) {
873                     compilerConfiguration.setMeminitial(value);
874                 } else {
875                     getLog().info("Invalid value for meminitial '" + meminitial + "'. Ignoring this option.");
876                 }
877             }
878 
879             if (!(maxmem == null || maxmem.isEmpty())) {
880                 String value = getMemoryValue(maxmem);
881 
882                 if (value != null) {
883                     compilerConfiguration.setMaxmem(value);
884                 } else {
885                     getLog().info("Invalid value for maxmem '" + maxmem + "'. Ignoring this option.");
886                 }
887             }
888         }
889 
890         compilerConfiguration.setExecutable(executable);
891 
892         compilerConfiguration.setWorkingDirectory(basedir);
893 
894         compilerConfiguration.setCompilerVersion(compilerVersion);
895 
896         compilerConfiguration.setBuildDirectory(buildDirectory);
897 
898         compilerConfiguration.setOutputFileName(outputFileName);
899 
900         if (CompilerConfiguration.CompilerReuseStrategy.AlwaysNew.getStrategy().equals(this.compilerReuseStrategy)) {
901             compilerConfiguration.setCompilerReuseStrategy(CompilerConfiguration.CompilerReuseStrategy.AlwaysNew);
902         } else if (CompilerConfiguration.CompilerReuseStrategy.ReuseSame.getStrategy()
903                 .equals(this.compilerReuseStrategy)) {
904             if (getRequestThreadCount() > 1) {
905                 if (!skipMultiThreadWarning) {
906                     getLog().warn("You are in a multi-thread build and compilerReuseStrategy is set to reuseSame."
907                             + " This can cause issues in some environments (os/jdk)!"
908                             + " Consider using reuseCreated strategy."
909                             + System.getProperty("line.separator")
910                             + "If your env is fine with reuseSame, you can skip this warning with the "
911                             + "configuration field skipMultiThreadWarning "
912                             + "or -Dmaven.compiler.skipMultiThreadWarning=true");
913                 }
914             }
915             compilerConfiguration.setCompilerReuseStrategy(CompilerConfiguration.CompilerReuseStrategy.ReuseSame);
916         } else {
917 
918             compilerConfiguration.setCompilerReuseStrategy(CompilerConfiguration.CompilerReuseStrategy.ReuseCreated);
919         }
920 
921         getLog().debug("CompilerReuseStrategy: "
922                 + compilerConfiguration.getCompilerReuseStrategy().getStrategy());
923 
924         compilerConfiguration.setForceJavacCompilerUse(forceLegacyJavacApi || forceJavacCompilerUse);
925 
926         boolean canUpdateTarget;
927 
928         IncrementalBuildHelper incrementalBuildHelper = new IncrementalBuildHelper(mojoExecution, session);
929 
930         final Set<File> sources;
931 
932         IncrementalBuildHelperRequest incrementalBuildHelperRequest = null;
933 
934         if (useIncrementalCompilation) {
935             getLog().debug("useIncrementalCompilation enabled");
936             try {
937                 canUpdateTarget = compiler.canUpdateTarget(compilerConfiguration);
938 
939                 sources = getCompileSources(compiler, compilerConfiguration);
940 
941                 preparePaths(sources);
942 
943                 incrementalBuildHelperRequest = new IncrementalBuildHelperRequest().inputFiles(sources);
944 
945                 
946                 String immutableOutputFile = (compiler.getCompilerOutputStyle()
947                                         .equals(CompilerOutputStyle.ONE_OUTPUT_FILE_FOR_ALL_INPUT_FILES)
948                                 && !canUpdateTarget)
949                         ? "immutable single output file"
950                         : null;
951                 String dependencyChanged = isDependencyChanged() ? "changed dependency" : null;
952                 String sourceChanged = isSourceChanged(compilerConfiguration, compiler) ? "changed source code" : null;
953                 String inputFileTreeChanged = hasInputFileTreeChanged(incrementalBuildHelper, sources)
954                         ? "added or removed source files"
955                         : null;
956 
957                 
958                 String cause = Stream.of(immutableOutputFile, dependencyChanged, sourceChanged, inputFileTreeChanged)
959                         .filter(Objects::nonNull)
960                         .findFirst()
961                         .orElse(null);
962 
963                 if (cause != null) {
964                     getLog().info("Recompiling the module because of "
965                             + MessageUtils.buffer().strong(cause) + ".");
966                     compilerConfiguration.setSourceFiles(sources);
967                 } else {
968                     getLog().info("Nothing to compile - all classes are up to date.");
969                     return;
970                 }
971             } catch (CompilerException e) {
972                 throw new MojoExecutionException("Error while computing stale sources.", e);
973             }
974         } else {
975             getLog().debug("useIncrementalCompilation disabled");
976 
977             Set<File> staleSources;
978             try {
979                 staleSources =
980                         computeStaleSources(compilerConfiguration, compiler, getSourceInclusionScanner(staleMillis));
981 
982                 canUpdateTarget = compiler.canUpdateTarget(compilerConfiguration);
983 
984                 if (compiler.getCompilerOutputStyle().equals(CompilerOutputStyle.ONE_OUTPUT_FILE_FOR_ALL_INPUT_FILES)
985                         && !canUpdateTarget) {
986                     getLog().info("RESCANNING!");
987                     
988                     String inputFileEnding = compiler.getInputFileEnding(compilerConfiguration);
989 
990                     staleSources = computeStaleSources(
991                             compilerConfiguration, compiler, getSourceInclusionScanner(inputFileEnding));
992                 }
993 
994             } catch (CompilerException e) {
995                 throw new MojoExecutionException("Error while computing stale sources.", e);
996             }
997 
998             if (staleSources.isEmpty()) {
999                 getLog().info("Nothing to compile - all classes are up to date.");
1000                 return;
1001             }
1002 
1003             compilerConfiguration.setSourceFiles(staleSources);
1004 
1005             try {
1006                 
1007                 sources = getCompileSources(compiler, compilerConfiguration);
1008 
1009                 if (getLog().isDebugEnabled()) {
1010                     getLog().debug("#sources: " + sources.size());
1011                     for (File file : sources) {
1012                         getLog().debug(file.getPath());
1013                     }
1014                 }
1015 
1016                 preparePaths(sources);
1017             } catch (CompilerException e) {
1018                 throw new MojoExecutionException("Error while computing stale sources.", e);
1019             }
1020         }
1021 
1022         
1023         compilerConfiguration.setClasspathEntries(getClasspathElements());
1024 
1025         compilerConfiguration.setModulepathEntries(getModulepathElements());
1026 
1027         compilerConfiguration.setIncludes(getIncludes());
1028 
1029         compilerConfiguration.setExcludes(getExcludes());
1030 
1031         Map<String, String> effectiveCompilerArguments = getCompilerArguments();
1032 
1033         String effectiveCompilerArgument = getCompilerArgument();
1034 
1035         if ((effectiveCompilerArguments != null) || (effectiveCompilerArgument != null) || (compilerArgs != null)) {
1036             if (effectiveCompilerArguments != null) {
1037                 for (Map.Entry<String, String> me : effectiveCompilerArguments.entrySet()) {
1038                     String key = me.getKey();
1039                     String value = me.getValue();
1040                     if (!key.startsWith("-")) {
1041                         key = "-" + key;
1042                     }
1043 
1044                     if (key.startsWith("-A") && (value != null && !value.isEmpty())) {
1045                         compilerConfiguration.addCompilerCustomArgument(key + "=" + value, null);
1046                     } else {
1047                         compilerConfiguration.addCompilerCustomArgument(key, value);
1048                     }
1049                 }
1050             }
1051             if (!(effectiveCompilerArgument == null || effectiveCompilerArgument.isEmpty())) {
1052                 compilerConfiguration.addCompilerCustomArgument(effectiveCompilerArgument, null);
1053             }
1054             if (compilerArgs != null) {
1055                 for (String arg : compilerArgs) {
1056                     compilerConfiguration.addCompilerCustomArgument(arg, null);
1057                 }
1058             }
1059         }
1060 
1061         
1062         
1063         
1064         if (getLog().isDebugEnabled()) {
1065             getLog().debug("Classpath:");
1066 
1067             for (String s : getClasspathElements()) {
1068                 getLog().debug(" " + s);
1069             }
1070 
1071             if (!getModulepathElements().isEmpty()) {
1072                 getLog().debug("Modulepath:");
1073                 for (String s : getModulepathElements()) {
1074                     getLog().debug(" " + s);
1075                 }
1076             }
1077 
1078             getLog().debug("Source roots:");
1079 
1080             for (String root : getCompileSourceRoots()) {
1081                 getLog().debug(" " + root);
1082             }
1083 
1084             try {
1085                 if (fork) {
1086                     if (compilerConfiguration.getExecutable() != null) {
1087                         getLog().debug("Executable: ");
1088                         getLog().debug(" " + compilerConfiguration.getExecutable());
1089                     }
1090                 }
1091 
1092                 String[] cl = compiler.createCommandLine(compilerConfiguration);
1093                 if (cl != null && cl.length > 0) {
1094                     StringBuilder sb = new StringBuilder();
1095                     sb.append(cl[0]);
1096                     for (int i = 1; i < cl.length; i++) {
1097                         sb.append(" ");
1098                         sb.append(cl[i]);
1099                     }
1100                     getLog().debug("Command line options:");
1101                     getLog().debug(sb);
1102                 }
1103             } catch (CompilerException ce) {
1104                 getLog().debug(ce);
1105             }
1106         }
1107 
1108         List<String> jpmsLines = new ArrayList<>();
1109 
1110         
1111         final List<String> runtimeArgs = Arrays.asList(
1112                 "--upgrade-module-path", "--add-exports", "--add-reads", "--add-modules", "--limit-modules");
1113 
1114         
1115         Iterator<Map.Entry<String, String>> entryIter =
1116                 compilerConfiguration.getCustomCompilerArgumentsEntries().iterator();
1117         while (entryIter.hasNext()) {
1118             Map.Entry<String, String> entry = entryIter.next();
1119 
1120             if (runtimeArgs.contains(entry.getKey())) {
1121                 jpmsLines.add(entry.getKey());
1122 
1123                 String value = entry.getValue();
1124                 if (value == null) {
1125                     entry = entryIter.next();
1126                     value = entry.getKey();
1127                 }
1128                 jpmsLines.add(value);
1129             } else if ("--patch-module".equals(entry.getKey())) {
1130                 String value = entry.getValue();
1131                 if (value == null) {
1132                     entry = entryIter.next();
1133                     value = entry.getKey();
1134                 }
1135 
1136                 String[] values = value.split("=");
1137 
1138                 StringBuilder patchModule = new StringBuilder(values[0]);
1139                 patchModule.append('=');
1140 
1141                 Set<String> patchModules = new LinkedHashSet<>();
1142                 Set<Path> sourceRoots = new HashSet<>(getCompileSourceRoots().size());
1143                 for (String sourceRoot : getCompileSourceRoots()) {
1144                     sourceRoots.add(Paths.get(sourceRoot));
1145                 }
1146 
1147                 String[] files = values[1].split(PS);
1148 
1149                 for (String file : files) {
1150                     Path filePath = Paths.get(file);
1151                     if (getOutputDirectory().toPath().equals(filePath)) {
1152                         patchModules.add("_"); 
1153                     } else if (getOutputDirectory().toPath().startsWith(filePath)) {
1154                         
1155                         continue;
1156                     } else if (sourceRoots.contains(filePath)) {
1157                         patchModules.add("_"); 
1158                     } else {
1159                         JavaModuleDescriptor descriptor = getPathElements().get(file);
1160 
1161                         if (descriptor == null) {
1162                             if (Files.isDirectory(filePath)) {
1163                                 patchModules.add(file);
1164                             } else {
1165                                 getLog().warn("Can't locate " + file);
1166                             }
1167                         } else if (!values[0].equals(descriptor.name())) {
1168                             patchModules.add(descriptor.name());
1169                         }
1170                     }
1171                 }
1172 
1173                 StringBuilder sb = new StringBuilder();
1174 
1175                 if (!patchModules.isEmpty()) {
1176                     for (String mod : patchModules) {
1177                         if (sb.length() > 0) {
1178                             sb.append(", ");
1179                         }
1180                         
1181                         sb.append(mod);
1182                     }
1183 
1184                     jpmsLines.add("--patch-module");
1185                     jpmsLines.add(patchModule + sb.toString());
1186                 }
1187             }
1188         }
1189 
1190         if (!jpmsLines.isEmpty()) {
1191             Path jpmsArgs = Paths.get(getOutputDirectory().getAbsolutePath(), "META-INF/jpms.args");
1192             try {
1193                 Files.createDirectories(jpmsArgs.getParent());
1194 
1195                 Files.write(jpmsArgs, jpmsLines, Charset.defaultCharset());
1196             } catch (IOException e) {
1197                 getLog().warn(e.getMessage());
1198             }
1199         }
1200 
1201         
1202         
1203         
1204 
1205         if (StringUtils.isEmpty(compilerConfiguration.getSourceEncoding())) {
1206             getLog().warn("File encoding has not been set, using platform encoding "
1207                     + MessageUtils.buffer().strong(Charset.defaultCharset())
1208                     + ", i.e. build is platform dependent!");
1209         }
1210 
1211         CompilerResult compilerResult;
1212 
1213         if (useIncrementalCompilation) {
1214             incrementalBuildHelperRequest.outputDirectory(getOutputDirectory());
1215 
1216             
1217             
1218             if (getGeneratedSourcesDirectory() != null) {
1219                 try (Stream<Path> walk =
1220                         Files.walk(getGeneratedSourcesDirectory().toPath())) {
1221                     walk.sorted(Comparator.reverseOrder()).map(Path::toFile).forEach(File::delete);
1222                     
1223                     Files.createDirectories(getGeneratedSourcesDirectory().toPath());
1224                 } catch (IOException ex) {
1225                     getLog().warn("I/O error deleting the annotation processing generated files: " + ex.getMessage());
1226                 }
1227             }
1228 
1229             incrementalBuildHelper.beforeRebuildExecution(incrementalBuildHelperRequest);
1230 
1231             getLog().debug("incrementalBuildHelper#beforeRebuildExecution");
1232         }
1233 
1234         try {
1235             compilerResult = compiler.performCompile(compilerConfiguration);
1236         } catch (Exception e) {
1237             
1238             throw new MojoExecutionException("Fatal error compiling", e);
1239         }
1240 
1241         if (createMissingPackageInfoClass
1242                 && compilerResult.isSuccess()
1243                 && compiler.getCompilerOutputStyle() == CompilerOutputStyle.ONE_OUTPUT_FILE_PER_INPUT_FILE) {
1244             try {
1245                 SourceMapping sourceMapping = getSourceMapping(compilerConfiguration, compiler);
1246                 createMissingPackageInfoClasses(compilerConfiguration, sourceMapping, sources);
1247             } catch (Exception e) {
1248                 getLog().warn("Error creating missing package info classes", e);
1249             }
1250         }
1251 
1252         if (outputTimestamp != null
1253                 && !outputTimestamp.isEmpty()
1254                 && (outputTimestamp.length() > 1 || Character.isDigit(outputTimestamp.charAt(0)))) {
1255             
1256             patchJdkModuleVersion(compilerResult, sources);
1257         }
1258 
1259         if (useIncrementalCompilation) {
1260             if (incrementalBuildHelperRequest.getOutputDirectory().exists()) {
1261                 getLog().debug("incrementalBuildHelper#afterRebuildExecution");
1262                 
1263                 incrementalBuildHelper.afterRebuildExecution(incrementalBuildHelperRequest);
1264             } else {
1265                 getLog().debug(
1266                                 "skip incrementalBuildHelper#afterRebuildExecution as the output directory doesn't exist");
1267             }
1268         }
1269 
1270         List<CompilerMessage> warnings = new ArrayList<>();
1271         List<CompilerMessage> errors = new ArrayList<>();
1272         List<CompilerMessage> others = new ArrayList<>();
1273         for (CompilerMessage message : compilerResult.getCompilerMessages()) {
1274             switch (message.getKind()) {
1275                 case ERROR:
1276                     errors.add(message);
1277                     break;
1278                 case WARNING:
1279                 case MANDATORY_WARNING:
1280                     warnings.add(message);
1281                     break;
1282                 default:
1283                     others.add(message);
1284                     break;
1285             }
1286         }
1287 
1288         if (failOnError && !compilerResult.isSuccess()) {
1289             for (CompilerMessage message : others) {
1290                 assert message.getKind() != CompilerMessage.Kind.ERROR
1291                         && message.getKind() != CompilerMessage.Kind.WARNING
1292                         && message.getKind() != CompilerMessage.Kind.MANDATORY_WARNING;
1293                 getLog().info(message.toString());
1294             }
1295             if (!warnings.isEmpty()) {
1296                 getLog().info("-------------------------------------------------------------");
1297                 getLog().warn("COMPILATION WARNING : ");
1298                 getLog().info("-------------------------------------------------------------");
1299                 for (CompilerMessage warning : warnings) {
1300                     getLog().warn(warning.toString());
1301                 }
1302                 getLog().info(warnings.size() + ((warnings.size() > 1) ? " warnings " : " warning"));
1303                 getLog().info("-------------------------------------------------------------");
1304             }
1305 
1306             if (!errors.isEmpty()) {
1307                 getLog().info("-------------------------------------------------------------");
1308                 getLog().error("COMPILATION ERROR : ");
1309                 getLog().info("-------------------------------------------------------------");
1310                 for (CompilerMessage error : errors) {
1311                     getLog().error(error.toString());
1312                 }
1313                 getLog().info(errors.size() + ((errors.size() > 1) ? " errors " : " error"));
1314                 getLog().info("-------------------------------------------------------------");
1315             }
1316 
1317             if (!errors.isEmpty()) {
1318                 throw new CompilationFailureException(errors);
1319             } else {
1320                 throw new CompilationFailureException(warnings);
1321             }
1322         } else {
1323             for (CompilerMessage message : compilerResult.getCompilerMessages()) {
1324                 switch (message.getKind()) {
1325                     case NOTE:
1326                     case OTHER:
1327                         getLog().info(message.toString());
1328                         break;
1329                     case ERROR:
1330                         getLog().error(message.toString());
1331                         break;
1332                     case MANDATORY_WARNING:
1333                     case WARNING:
1334                     default:
1335                         getLog().warn(message.toString());
1336                         break;
1337                 }
1338             }
1339         }
1340     }
1341 
1342     private void createMissingPackageInfoClasses(
1343             CompilerConfiguration compilerConfiguration, SourceMapping sourceMapping, Set<File> sources)
1344             throws InclusionScanException, IOException {
1345         for (File source : sources) {
1346             String path = source.toString();
1347             if (path.endsWith(File.separator + "package-info.java")) {
1348                 for (String root : getCompileSourceRoots()) {
1349                     root = root + File.separator;
1350                     if (path.startsWith(root)) {
1351                         String rel = path.substring(root.length());
1352                         Set<File> files = sourceMapping.getTargetFiles(getOutputDirectory(), rel);
1353                         for (File file : files) {
1354                             if (!file.exists()) {
1355                                 File parentFile = file.getParentFile();
1356 
1357                                 if (!parentFile.exists()) {
1358                                     Files.createDirectories(parentFile.toPath());
1359                                 }
1360 
1361                                 byte[] bytes = generatePackage(compilerConfiguration, rel);
1362                                 Files.write(file.toPath(), bytes);
1363                             }
1364                         }
1365                     }
1366                 }
1367             }
1368         }
1369     }
1370 
1371     private byte[] generatePackage(CompilerConfiguration compilerConfiguration, String javaFile) {
1372         int version = getOpcode(compilerConfiguration);
1373         String internalPackageName = javaFile.substring(0, javaFile.length() - ".java".length());
1374         if (File.separatorChar != '/') {
1375             internalPackageName = internalPackageName.replace(File.separatorChar, '/');
1376         }
1377         ClassWriter cw = new ClassWriter(0);
1378         cw.visit(
1379                 version,
1380                 Opcodes.ACC_SYNTHETIC | Opcodes.ACC_ABSTRACT | Opcodes.ACC_INTERFACE,
1381                 internalPackageName,
1382                 null,
1383                 "java/lang/Object",
1384                 null);
1385         cw.visitSource("package-info.java", null);
1386         return cw.toByteArray();
1387     }
1388 
1389     private int getOpcode(CompilerConfiguration compilerConfiguration) {
1390         String version = compilerConfiguration.getReleaseVersion();
1391         if (version == null) {
1392             version = compilerConfiguration.getTargetVersion();
1393             if (version == null) {
1394                 version = "1.5";
1395             }
1396         }
1397         if (version.startsWith("1.")) {
1398             version = version.substring(2);
1399         }
1400         int iVersion = Integer.parseInt(version);
1401         if (iVersion < 2) {
1402             throw new IllegalArgumentException("Unsupported java version '" + version + "'");
1403         }
1404         return iVersion - 2 + Opcodes.V1_2;
1405     }
1406 
1407     protected boolean isTestCompile() {
1408         return false;
1409     }
1410 
1411     
1412 
1413 
1414     private Set<File> getCompileSources(Compiler compiler, CompilerConfiguration compilerConfiguration)
1415             throws MojoExecutionException, CompilerException {
1416         String inputFileEnding = compiler.getInputFileEnding(compilerConfiguration);
1417         if (inputFileEnding == null || inputFileEnding.isEmpty()) {
1418             
1419             
1420             inputFileEnding = ".*";
1421         }
1422         SourceInclusionScanner scanner = getSourceInclusionScanner(inputFileEnding);
1423 
1424         SourceMapping mapping = getSourceMapping(compilerConfiguration, compiler);
1425 
1426         scanner.addSourceMapping(mapping);
1427 
1428         Set<File> compileSources = new HashSet<>();
1429 
1430         for (String sourceRoot : getCompileSourceRoots()) {
1431             File rootFile = new File(sourceRoot);
1432 
1433             if (!rootFile.isDirectory()
1434                     || rootFile.getAbsoluteFile().equals(compilerConfiguration.getGeneratedSourcesDirectory())) {
1435                 continue;
1436             }
1437 
1438             try {
1439                 compileSources.addAll(scanner.getIncludedSources(rootFile, null));
1440             } catch (InclusionScanException e) {
1441                 throw new MojoExecutionException(
1442                         "Error scanning source root: '" + sourceRoot + "' for stale files to recompile.", e);
1443             }
1444         }
1445 
1446         return compileSources;
1447     }
1448 
1449     protected abstract Set<String> getIncludes();
1450 
1451     protected abstract Set<String> getExcludes();
1452 
1453     
1454 
1455 
1456 
1457 
1458     private boolean isSourceChanged(CompilerConfiguration compilerConfiguration, Compiler compiler) {
1459         Set<File> staleSources = Collections.emptySet();
1460         try {
1461             staleSources = computeStaleSources(compilerConfiguration, compiler, getSourceInclusionScanner(staleMillis));
1462         } catch (MojoExecutionException | CompilerException ex) {
1463             
1464             getLog().warn("Cannot detect stale sources.");
1465             return false;
1466         }
1467 
1468         if (getLog().isDebugEnabled() || showCompilationChanges) {
1469             for (File f : staleSources) {
1470                 getLog().info("\tStale source detected: " + f.getAbsolutePath());
1471             }
1472         }
1473         return !staleSources.isEmpty();
1474     }
1475 
1476     
1477 
1478 
1479 
1480 
1481     protected int getRequestThreadCount() {
1482         return session.getRequest().getDegreeOfConcurrency();
1483     }
1484 
1485     protected Date getBuildStartTime() {
1486         return getBuildStartTimeInstant().map(Date::from).orElseGet(Date::new);
1487     }
1488 
1489     private Optional<Instant> getBuildStartTimeInstant() {
1490         return Optional.ofNullable(session.getRequest())
1491                 .map(MavenExecutionRequest::getStartTime)
1492                 .map(Date::toInstant)
1493                 .map(i -> i.truncatedTo(ChronoUnit.MILLIS));
1494     }
1495 
1496     private String getMemoryValue(String setting) {
1497         String value = null;
1498 
1499         
1500         if (isDigits(setting)) {
1501             value = setting + "m";
1502         } else if ((isDigits(setting.substring(0, setting.length() - 1)))
1503                 && (setting.toLowerCase().endsWith("m"))) {
1504             value = setting;
1505         }
1506         return value;
1507     }
1508 
1509     protected final Toolchain getToolchain() {
1510         Toolchain tc = null;
1511 
1512         if (jdkToolchain != null) {
1513             List<Toolchain> tcs = toolchainManager.getToolchains(session, "jdk", jdkToolchain);
1514             if (tcs != null && !tcs.isEmpty()) {
1515                 tc = tcs.get(0);
1516             }
1517         }
1518 
1519         if (tc == null) {
1520             tc = toolchainManager.getToolchainFromBuildContext("jdk", session);
1521         }
1522 
1523         return tc;
1524     }
1525 
1526     private boolean isDigits(String string) {
1527         for (int i = 0; i < string.length(); i++) {
1528             if (!Character.isDigit(string.charAt(i))) {
1529                 return false;
1530             }
1531         }
1532         return true;
1533     }
1534 
1535     private Set<File> computeStaleSources(
1536             CompilerConfiguration compilerConfiguration, Compiler compiler, SourceInclusionScanner scanner)
1537             throws MojoExecutionException, CompilerException {
1538         SourceMapping mapping = getSourceMapping(compilerConfiguration, compiler);
1539 
1540         File outputDirectory;
1541         CompilerOutputStyle outputStyle = compiler.getCompilerOutputStyle();
1542         if (outputStyle == CompilerOutputStyle.ONE_OUTPUT_FILE_FOR_ALL_INPUT_FILES) {
1543             outputDirectory = buildDirectory;
1544         } else {
1545             outputDirectory = getOutputDirectory();
1546         }
1547 
1548         scanner.addSourceMapping(mapping);
1549 
1550         Set<File> staleSources = new HashSet<>();
1551 
1552         for (String sourceRoot : getCompileSourceRoots()) {
1553             File rootFile = new File(sourceRoot);
1554 
1555             if (!rootFile.isDirectory()) {
1556                 continue;
1557             }
1558 
1559             try {
1560                 staleSources.addAll(scanner.getIncludedSources(rootFile, outputDirectory));
1561             } catch (InclusionScanException e) {
1562                 throw new MojoExecutionException(
1563                         "Error scanning source root: \'" + sourceRoot + "\' for stale files to recompile.", e);
1564             }
1565         }
1566 
1567         return staleSources;
1568     }
1569 
1570     private SourceMapping getSourceMapping(CompilerConfiguration compilerConfiguration, Compiler compiler)
1571             throws CompilerException, MojoExecutionException {
1572         CompilerOutputStyle outputStyle = compiler.getCompilerOutputStyle();
1573 
1574         SourceMapping mapping;
1575         if (outputStyle == CompilerOutputStyle.ONE_OUTPUT_FILE_PER_INPUT_FILE) {
1576             mapping = new SuffixMapping(
1577                     compiler.getInputFileEnding(compilerConfiguration),
1578                     compiler.getOutputFileEnding(compilerConfiguration));
1579         } else if (outputStyle == CompilerOutputStyle.ONE_OUTPUT_FILE_FOR_ALL_INPUT_FILES) {
1580             mapping = new SingleTargetSourceMapping(
1581                     compiler.getInputFileEnding(compilerConfiguration), compiler.getOutputFile(compilerConfiguration));
1582 
1583         } else {
1584             throw new MojoExecutionException("Unknown compiler output style: '" + outputStyle + "'.");
1585         }
1586         return mapping;
1587     }
1588 
1589     
1590 
1591 
1592 
1593     private static List<String> removeEmptyCompileSourceRoots(List<String> compileSourceRootsList) {
1594         List<String> newCompileSourceRootsList = new ArrayList<>();
1595         if (compileSourceRootsList != null) {
1596             
1597             for (String srcDir : compileSourceRootsList) {
1598                 if (!newCompileSourceRootsList.contains(srcDir) && new File(srcDir).exists()) {
1599                     newCompileSourceRootsList.add(srcDir);
1600                 }
1601             }
1602         }
1603         return newCompileSourceRootsList;
1604     }
1605 
1606     
1607 
1608 
1609 
1610 
1611 
1612 
1613     protected boolean isDependencyChanged() {
1614         final Instant buildStartTime = getBuildStartTimeInstant().orElse(null);
1615         if (buildStartTime == null) {
1616             
1617             getLog().debug("Cannot determine build start time, skipping incremental build detection.");
1618             return false;
1619         }
1620 
1621         if (fileExtensions == null || fileExtensions.isEmpty()) {
1622             fileExtensions = new HashSet<>(Arrays.asList("class", "jar"));
1623         }
1624 
1625         List<String> pathElements = new ArrayList<>();
1626         pathElements.addAll(getClasspathElements());
1627         pathElements.addAll(getModulepathElements());
1628 
1629         for (String pathElement : pathElements) {
1630             Path artifactPath = Paths.get(pathElement);
1631 
1632             
1633             if (Files.isDirectory(artifactPath)
1634                     && !artifactPath.equals(getOutputDirectory().toPath())) {
1635                 try (Stream<Path> walk = Files.walk(artifactPath)) {
1636                     if (walk.anyMatch(p -> hasNewFile(p, buildStartTime))) {
1637                         return true;
1638                     }
1639                 } catch (IOException ex) {
1640                     
1641                     getLog().warn("I/O error walking the path: " + ex.getMessage());
1642                     return false;
1643                 }
1644             } else if (hasNewFile(artifactPath, buildStartTime)) {
1645                 return true;
1646             }
1647         }
1648 
1649         
1650         return false;
1651     }
1652 
1653     
1654 
1655 
1656 
1657 
1658     private boolean hasNewFile(Path file, Instant buildStartTime) {
1659         if (Files.isRegularFile(file)
1660                 && fileExtensions.contains(
1661                         FileUtils.extension(file.getFileName().toString()))) {
1662             try {
1663                 Instant lastModifiedTime = Files.getLastModifiedTime(file)
1664                         .toInstant()
1665                         .minusMillis(staleMillis)
1666                         .truncatedTo(ChronoUnit.MILLIS);
1667                 boolean hasChanged = lastModifiedTime.isAfter(buildStartTime);
1668                 if (hasChanged && (getLog().isDebugEnabled() || showCompilationChanges)) {
1669                     getLog().info("\tNew dependency detected: " + file.toAbsolutePath());
1670                 }
1671                 return hasChanged;
1672             } catch (IOException ex) {
1673                 
1674                 getLog().warn("I/O error reading the lastModifiedTime: " + ex.getMessage());
1675             }
1676         }
1677 
1678         return false;
1679     }
1680 
1681     private List<String> resolveProcessorPathEntries() throws MojoExecutionException {
1682         if (annotationProcessorPaths == null || annotationProcessorPaths.isEmpty()) {
1683             return null;
1684         }
1685 
1686         try {
1687             List<org.eclipse.aether.graph.Dependency> dependencies = convertToDependencies(annotationProcessorPaths);
1688             List<org.eclipse.aether.graph.Dependency> managedDependencies =
1689                     getManagedDependenciesForAnnotationProcessorPaths();
1690             CollectRequest collectRequest =
1691                     new CollectRequest(dependencies, managedDependencies, project.getRemoteProjectRepositories());
1692             DependencyRequest dependencyRequest = new DependencyRequest();
1693             dependencyRequest.setCollectRequest(collectRequest);
1694             DependencyResult dependencyResult =
1695                     repositorySystem.resolveDependencies(session.getRepositorySession(), dependencyRequest);
1696 
1697             return dependencyResult.getArtifactResults().stream()
1698                     .map(resolved -> resolved.getArtifact().getFile().getAbsolutePath())
1699                     .collect(Collectors.toList());
1700         } catch (Exception e) {
1701             throw new MojoExecutionException(
1702                     "Resolution of annotationProcessorPath dependencies failed: " + e.getLocalizedMessage(), e);
1703         }
1704     }
1705 
1706     private List<org.eclipse.aether.graph.Dependency> convertToDependencies(
1707             List<DependencyCoordinate> annotationProcessorPaths) throws MojoExecutionException {
1708         List<org.eclipse.aether.graph.Dependency> dependencies = new ArrayList<>();
1709         for (DependencyCoordinate annotationProcessorPath : annotationProcessorPaths) {
1710             ArtifactHandler handler = artifactHandlerManager.getArtifactHandler(annotationProcessorPath.getType());
1711             String version = getAnnotationProcessorPathVersion(annotationProcessorPath);
1712             Artifact artifact = new DefaultArtifact(
1713                     annotationProcessorPath.getGroupId(),
1714                     annotationProcessorPath.getArtifactId(),
1715                     annotationProcessorPath.getClassifier(),
1716                     handler.getExtension(),
1717                     version);
1718             Set<Exclusion> exclusions = convertToAetherExclusions(annotationProcessorPath.getExclusions());
1719             dependencies.add(new org.eclipse.aether.graph.Dependency(artifact, JavaScopes.RUNTIME, false, exclusions));
1720         }
1721         return dependencies;
1722     }
1723 
1724     private String getAnnotationProcessorPathVersion(DependencyCoordinate annotationProcessorPath)
1725             throws MojoExecutionException {
1726         String configuredVersion = annotationProcessorPath.getVersion();
1727         if (configuredVersion != null) {
1728             return configuredVersion;
1729         } else {
1730             List<Dependency> managedDependencies = getProjectManagedDependencies();
1731             return findManagedVersion(annotationProcessorPath, managedDependencies)
1732                     .orElseThrow(() -> new MojoExecutionException(String.format(
1733                             "Cannot find version for annotation processor path '%s'. The version needs to be either"
1734                                     + " provided directly in the plugin configuration or via dependency management.",
1735                             annotationProcessorPath)));
1736         }
1737     }
1738 
1739     private Optional<String> findManagedVersion(
1740             DependencyCoordinate dependencyCoordinate, List<Dependency> managedDependencies) {
1741         return managedDependencies.stream()
1742                 .filter(dep -> Objects.equals(dep.getGroupId(), dependencyCoordinate.getGroupId())
1743                         && Objects.equals(dep.getArtifactId(), dependencyCoordinate.getArtifactId())
1744                         && Objects.equals(dep.getClassifier(), dependencyCoordinate.getClassifier())
1745                         && Objects.equals(dep.getType(), dependencyCoordinate.getType()))
1746                 .findAny()
1747                 .map(org.apache.maven.model.Dependency::getVersion);
1748     }
1749 
1750     private List<org.eclipse.aether.graph.Dependency> getManagedDependenciesForAnnotationProcessorPaths() {
1751         if (!annotationProcessorPathsUseDepMgmt) {
1752             return Collections.emptyList();
1753         }
1754         List<Dependency> projectManagedDependencies = getProjectManagedDependencies();
1755         ArtifactTypeRegistry artifactTypeRegistry =
1756                 session.getRepositorySession().getArtifactTypeRegistry();
1757 
1758         return projectManagedDependencies.stream()
1759                 .map(dep -> RepositoryUtils.toDependency(dep, artifactTypeRegistry))
1760                 .collect(Collectors.toList());
1761     }
1762 
1763     private List<Dependency> getProjectManagedDependencies() {
1764         DependencyManagement dependencyManagement = project.getDependencyManagement();
1765         if (dependencyManagement == null || dependencyManagement.getDependencies() == null) {
1766             return Collections.emptyList();
1767         }
1768         return dependencyManagement.getDependencies();
1769     }
1770 
1771     private Set<Exclusion> convertToAetherExclusions(Set<DependencyExclusion> exclusions) {
1772         if (exclusions == null || exclusions.isEmpty()) {
1773             return Collections.emptySet();
1774         }
1775         Set<Exclusion> aetherExclusions = new HashSet<>();
1776         for (DependencyExclusion exclusion : exclusions) {
1777             Exclusion aetherExclusion = new Exclusion(
1778                     exclusion.getGroupId(),
1779                     exclusion.getArtifactId(),
1780                     exclusion.getClassifier(),
1781                     exclusion.getExtension());
1782             aetherExclusions.add(aetherExclusion);
1783         }
1784         return aetherExclusions;
1785     }
1786 
1787     private void writePlugin(MessageBuilder mb) {
1788         mb.a("    <plugin>").newline();
1789         mb.a("      <groupId>org.apache.maven.plugins</groupId>").newline();
1790         mb.a("      <artifactId>maven-compiler-plugin</artifactId>").newline();
1791 
1792         String version = getMavenCompilerPluginVersion();
1793         if (version != null) {
1794             mb.a("      <version>").a(version).a("</version>").newline();
1795         }
1796         writeConfig(mb);
1797 
1798         mb.a("    </plugin>").newline();
1799     }
1800 
1801     private void writeConfig(MessageBuilder mb) {
1802         mb.a("      <configuration>").newline();
1803 
1804         if (release != null) {
1805             mb.a("        <release>").a(release).a("</release>").newline();
1806         } else if (JavaVersion.JAVA_VERSION.isAtLeast("9")) {
1807             String rls = target.replaceAll(".\\.", "");
1808             
1809             mb.a("        <release>").a(rls).a("</release>").newline();
1810         } else {
1811             mb.a("        <source>").a(source).a("</source>").newline();
1812             mb.a("        <target>").a(target).a("</target>").newline();
1813         }
1814         mb.a("      </configuration>").newline();
1815     }
1816 
1817     private String getMavenCompilerPluginVersion() {
1818         Properties pomProperties = new Properties();
1819 
1820         try (InputStream is = AbstractCompilerMojo.class.getResourceAsStream(
1821                 "/META-INF/maven/org.apache.maven.plugins/maven-compiler-plugin/pom.properties")) {
1822             if (is != null) {
1823                 pomProperties.load(is);
1824             }
1825         } catch (IOException e) {
1826             
1827         }
1828 
1829         return pomProperties.getProperty("version");
1830     }
1831 
1832     private boolean hasInputFileTreeChanged(IncrementalBuildHelper ibh, Set<File> inputFiles) {
1833         Path mojoConfigBase;
1834         try {
1835             mojoConfigBase = ibh.getMojoStatusDirectory().toPath();
1836         } catch (MojoExecutionException e) {
1837             
1838             getLog().warn("Error reading mojo status directory.");
1839             return false;
1840         }
1841         Path mojoConfigFile = mojoConfigBase.resolve(INPUT_FILES_LST_FILENAME);
1842 
1843         Set<String> oldInputFiles = Collections.emptySet();
1844         if (Files.isRegularFile(mojoConfigFile)) {
1845             try {
1846                 oldInputFiles = new HashSet<>(Files.readAllLines(mojoConfigFile));
1847             } catch (IOException e) {
1848                 
1849                 getLog().warn("Error while reading old mojo status: " + mojoConfigFile);
1850                 return false;
1851             }
1852         }
1853 
1854         Set<String> newInputFiles = inputFiles.stream()
1855                 .sorted()
1856                 .map(File::getAbsolutePath)
1857                 .collect(Collectors.toCollection(LinkedHashSet::new));
1858 
1859         try {
1860             Files.write(mojoConfigFile, newInputFiles);
1861         } catch (IOException e) {
1862             
1863             getLog().warn("Error while writing new mojo status: " + mojoConfigFile);
1864             return false;
1865         }
1866 
1867         DeltaList<String> inputTreeChanges = new DeltaList<>(oldInputFiles, newInputFiles);
1868         if (getLog().isDebugEnabled() || showCompilationChanges) {
1869             for (String fileAdded : inputTreeChanges.getAdded()) {
1870                 getLog().info("\tInput tree files (+): " + fileAdded);
1871             }
1872             for (String fileRemoved : inputTreeChanges.getRemoved()) {
1873                 getLog().info("\tInput tree files (-): " + fileRemoved);
1874             }
1875         }
1876 
1877         return inputTreeChanges.hasChanged();
1878     }
1879 
1880     public void setTarget(String target) {
1881         this.target = target;
1882         targetOrReleaseSet = true;
1883     }
1884 
1885     public void setRelease(String release) {
1886         this.release = release;
1887         targetOrReleaseSet = true;
1888     }
1889 
1890     final String getImplicit() {
1891         return implicit;
1892     }
1893 
1894     
1895 
1896 
1897 
1898 
1899 
1900 
1901 
1902 
1903     private void patchJdkModuleVersion(CompilerResult compilerResult, Set<File> sources) throws MojoExecutionException {
1904         if (compilerResult.isSuccess() && getModuleDeclaration(sources).isPresent()) {
1905             Path moduleDescriptor = getOutputDirectory().toPath().resolve("module-info.class");
1906             if (Files.isRegularFile(moduleDescriptor)) {
1907                 try {
1908                     final byte[] descriptorOriginal = Files.readAllBytes(moduleDescriptor);
1909                     final byte[] descriptorMod =
1910                             ModuleInfoTransformer.transform(descriptorOriginal, getRelease(), getLog());
1911                     if (descriptorMod != null) {
1912                         Files.write(moduleDescriptor, descriptorMod);
1913                     }
1914                 } catch (IOException ex) {
1915                     throw new MojoExecutionException("Error reading or writing module-info.class", ex);
1916                 }
1917             }
1918         }
1919     }
1920 }