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