1 package org.apache.maven.plugin.compiler;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.File;
23 import java.io.IOException;
24 import java.util.ArrayList;
25 import java.util.Collection;
26 import java.util.Collections;
27 import java.util.HashSet;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.Set;
31
32 import org.apache.maven.artifact.Artifact;
33 import org.apache.maven.plugin.MojoExecutionException;
34 import org.apache.maven.plugin.compiler.module.JavaModuleDescriptor;
35 import org.apache.maven.plugin.compiler.module.ModuleInfoParser;
36 import org.apache.maven.plugin.compiler.module.ProjectAnalyzer;
37 import org.apache.maven.plugin.compiler.module.ProjectAnalyzerRequest;
38 import org.apache.maven.plugin.compiler.module.ProjectAnalyzerResult;
39 import org.apache.maven.plugins.annotations.Component;
40 import org.apache.maven.plugins.annotations.LifecyclePhase;
41 import org.apache.maven.plugins.annotations.Mojo;
42 import org.apache.maven.plugins.annotations.Parameter;
43 import org.apache.maven.plugins.annotations.ResolutionScope;
44 import org.apache.maven.project.MavenProject;
45 import org.apache.maven.shared.utils.StringUtils;
46 import org.apache.maven.shared.utils.logging.MessageUtils;
47 import org.codehaus.plexus.compiler.util.scan.SimpleSourceInclusionScanner;
48 import org.codehaus.plexus.compiler.util.scan.SourceInclusionScanner;
49 import org.codehaus.plexus.compiler.util.scan.StaleSourceScanner;
50
51
52
53
54
55
56
57
58 @Mojo( name = "compile", defaultPhase = LifecyclePhase.COMPILE, threadSafe = true,
59 requiresDependencyResolution = ResolutionScope.COMPILE )
60 public class CompilerMojo
61 extends AbstractCompilerMojo
62 {
63
64
65
66 @Parameter( defaultValue = "${project.compileSourceRoots}", readonly = true, required = true )
67 private List<String> compileSourceRoots;
68
69
70
71
72 @Parameter( defaultValue = "${project.build.outputDirectory}", required = true, readonly = true )
73 private File outputDirectory;
74
75
76
77
78
79
80 @Parameter( defaultValue = "${project.artifact}", readonly = true, required = true )
81 private Artifact projectArtifact;
82
83
84
85
86 @Parameter
87 private Set<String> includes = new HashSet<String>();
88
89
90
91
92 @Parameter
93 private Set<String> excludes = new HashSet<String>();
94
95
96
97
98
99
100
101
102 @Parameter( defaultValue = "${project.build.directory}/generated-sources/annotations" )
103 private File generatedSourcesDirectory;
104
105
106
107
108
109 @Parameter( property = "maven.main.skip" )
110 private boolean skipMain;
111
112 @Parameter( defaultValue = "${project.compileClasspathElements}", readonly = true, required = true )
113 private List<String> compilePath;
114
115 @Parameter
116 private boolean allowPartialRequirements;
117
118 @Component( hint = "qdox" )
119 private ModuleInfoParser moduleInfoParser;
120
121 @Component
122 private ProjectAnalyzer projectAnalyzer;
123
124 private List<String> classpathElements;
125
126 private List<String> modulepathElements;
127
128 protected List<String> getCompileSourceRoots()
129 {
130 return compileSourceRoots;
131 }
132
133 protected List<String> getClasspathElements()
134 {
135 return classpathElements;
136 }
137
138 @Override
139 protected List<String> getModulepathElements()
140 {
141 return modulepathElements;
142 }
143
144 protected File getOutputDirectory()
145 {
146 return outputDirectory;
147 }
148
149 public void execute()
150 throws MojoExecutionException, CompilationFailureException
151 {
152 if ( skipMain )
153 {
154 getLog().info( "Not compiling main sources" );
155 return;
156 }
157
158 super.execute();
159
160 if ( outputDirectory.isDirectory() )
161 {
162 projectArtifact.setFile( outputDirectory );
163 }
164 }
165
166 @Override
167 protected void preparePaths( Set<File> sourceFiles )
168 {
169 assert compilePath != null;
170
171 JavaModuleDescriptor moduleDescriptor = null;
172
173 boolean hasModuleDescriptor = false;
174 for ( File sourceFile : sourceFiles )
175 {
176 if ( "module-info.java".equals( sourceFile.getName() ) )
177 {
178 try
179 {
180 moduleDescriptor = moduleInfoParser.getModuleDescriptor( sourceFile.getParentFile() );
181 }
182 catch ( IOException e )
183 {
184 getLog().warn( "Failed to parse module-info.java: " + e.getMessage() );
185 }
186 hasModuleDescriptor = true;
187 break;
188 }
189 }
190
191 if ( hasModuleDescriptor )
192 {
193
194
195
196
197 modulepathElements = new ArrayList<String>( compilePath.size() );
198 classpathElements = new ArrayList<String>( compilePath.size() );
199
200 ProjectAnalyzerResult analyzerResult;
201 try
202 {
203 Collection<File> dependencyArtifacts = getCompileClasspathElements( getProject() );
204
205 ProjectAnalyzerRequest analyzerRequest = new ProjectAnalyzerRequest()
206 .setBaseModuleDescriptor( moduleDescriptor )
207 .setDependencyArtifacts( dependencyArtifacts );
208
209 analyzerResult = projectAnalyzer.analyze( analyzerRequest );
210
211 if ( !analyzerResult.getRequiredAutomaticModules().isEmpty() )
212 {
213 boolean filenameBased = false;
214
215 for ( String automodule : analyzerResult.getRequiredAutomaticModules() )
216 {
217 filenameBased =
218 ProjectAnalyzerResult.ModuleNameSource.FILENAME.equals(
219 analyzerResult.getModuleNameSource( automodule ) );
220
221 if ( filenameBased )
222 {
223 final String message = "Required automodules detected. "
224 + "Please don't publish this project to a public artifact repository!";
225
226 if ( moduleDescriptor.exports().isEmpty() )
227 {
228
229 getLog().info( message );
230 }
231 else
232 {
233
234 writeBoxedWarning( message );
235 }
236
237 break;
238 }
239 }
240 }
241
242 for ( Map.Entry<File, JavaModuleDescriptor> entry : analyzerResult.getPathElements().entrySet() )
243 {
244 if ( !allowPartialRequirements )
245 {
246 modulepathElements.add( entry.getKey().getPath() );
247 }
248 else if ( entry.getValue() == null )
249 {
250 classpathElements.add( entry.getKey().getPath() );
251 }
252 else if ( analyzerResult.getRequiredNormalModules().contains( entry.getValue().name() ) )
253 {
254 modulepathElements.add( entry.getKey().getPath() );
255 }
256 else if ( analyzerResult.getRequiredAutomaticModules().contains( entry.getValue().name() ) )
257 {
258 modulepathElements.add( entry.getKey().getPath() );
259 }
260 else
261 {
262 classpathElements.add( entry.getKey().getPath() );
263 }
264 }
265 }
266 catch ( IOException e )
267 {
268 getLog().warn( e.getMessage() );
269 }
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286 }
287 else
288 {
289 classpathElements = compilePath;
290 modulepathElements = Collections.emptyList();
291 }
292 }
293
294 private List<File> getCompileClasspathElements( MavenProject project )
295 {
296 List<File> list = new ArrayList<File>( project.getArtifacts().size() + 1 );
297
298 list.add( new File( project.getBuild().getOutputDirectory() ) );
299
300 for ( Artifact a : project.getArtifacts() )
301 {
302 list.add( a.getFile() );
303 }
304 return list;
305 }
306
307 protected SourceInclusionScanner getSourceInclusionScanner( int staleMillis )
308 {
309 SourceInclusionScanner scanner;
310
311 if ( includes.isEmpty() && excludes.isEmpty() )
312 {
313 scanner = new StaleSourceScanner( staleMillis );
314 }
315 else
316 {
317 if ( includes.isEmpty() )
318 {
319 includes.add( "**/*.java" );
320 }
321 scanner = new StaleSourceScanner( staleMillis, includes, excludes );
322 }
323
324 return scanner;
325 }
326
327 protected SourceInclusionScanner getSourceInclusionScanner( String inputFileEnding )
328 {
329 SourceInclusionScanner scanner;
330
331
332 String defaultIncludePattern = "**/*" + ( inputFileEnding.startsWith( "." ) ? "" : "." ) + inputFileEnding;
333
334 if ( includes.isEmpty() && excludes.isEmpty() )
335 {
336 includes = Collections.singleton( defaultIncludePattern );
337 scanner = new SimpleSourceInclusionScanner( includes, Collections.<String>emptySet() );
338 }
339 else
340 {
341 if ( includes.isEmpty() )
342 {
343 includes.add( defaultIncludePattern );
344 }
345 scanner = new SimpleSourceInclusionScanner( includes, excludes );
346 }
347
348 return scanner;
349 }
350
351 protected String getSource()
352 {
353 return source;
354 }
355
356 protected String getTarget()
357 {
358 return target;
359 }
360
361 @Override
362 protected String getRelease()
363 {
364 return release;
365 }
366
367 protected String getCompilerArgument()
368 {
369 return compilerArgument;
370 }
371
372 protected Map<String, String> getCompilerArguments()
373 {
374 return compilerArguments;
375 }
376
377 protected File getGeneratedSourcesDirectory()
378 {
379 return generatedSourcesDirectory;
380 }
381
382 private void writeBoxedWarning( String message )
383 {
384 String line = StringUtils.repeat( "*", message.length() + 4 );
385 getLog().warn( line );
386 getLog().warn( "* " + MessageUtils.buffer().strong( message ) + " *" );
387 getLog().warn( line );
388 }
389 }