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