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.LinkedHashMap;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.Set;
32
33 import org.apache.maven.plugin.MojoExecutionException;
34 import org.apache.maven.plugins.annotations.LifecyclePhase;
35 import org.apache.maven.plugins.annotations.Mojo;
36 import org.apache.maven.plugins.annotations.Parameter;
37 import org.apache.maven.plugins.annotations.ResolutionScope;
38 import org.apache.maven.toolchain.Toolchain;
39 import org.apache.maven.toolchain.java.DefaultJavaToolChain;
40 import org.codehaus.plexus.compiler.util.scan.SimpleSourceInclusionScanner;
41 import org.codehaus.plexus.compiler.util.scan.SourceInclusionScanner;
42 import org.codehaus.plexus.compiler.util.scan.StaleSourceScanner;
43 import org.codehaus.plexus.languages.java.jpms.JavaModuleDescriptor;
44 import org.codehaus.plexus.languages.java.jpms.LocationManager;
45 import org.codehaus.plexus.languages.java.jpms.ResolvePathsRequest;
46 import org.codehaus.plexus.languages.java.jpms.ResolvePathsResult;
47
48
49
50
51
52
53
54
55 @Mojo( name = "testCompile", defaultPhase = LifecyclePhase.TEST_COMPILE, threadSafe = true,
56 requiresDependencyResolution = ResolutionScope.TEST )
57 public class TestCompilerMojo
58 extends AbstractCompilerMojo
59 {
60
61
62
63
64 @Parameter ( property = "maven.test.skip" )
65 private boolean skip;
66
67
68
69
70 @Parameter ( defaultValue = "${project.testCompileSourceRoots}", readonly = true, required = true )
71 private List<String> compileSourceRoots;
72
73
74
75
76 @Parameter ( defaultValue = "${project.build.testOutputDirectory}", required = true, readonly = true )
77 private File outputDirectory;
78
79
80
81
82 @Parameter
83 private Set<String> testIncludes = new HashSet<String>();
84
85
86
87
88 @Parameter
89 private Set<String> testExcludes = new HashSet<String>();
90
91
92
93
94
95
96 @Parameter ( property = "maven.compiler.testSource" )
97 private String testSource;
98
99
100
101
102
103
104 @Parameter ( property = "maven.compiler.testTarget" )
105 private String testTarget;
106
107
108
109
110
111
112 @Parameter ( property = "maven.compiler.testRelease" )
113 private String testRelease;
114
115
116
117
118
119
120
121
122
123
124
125
126 @Parameter
127 private Map<String, String> testCompilerArguments;
128
129
130
131
132
133
134
135
136
137
138
139
140 @Parameter
141 private String testCompilerArgument;
142
143
144
145
146
147
148
149
150
151 @Parameter ( defaultValue = "${project.build.directory}/generated-test-sources/test-annotations" )
152 private File generatedTestSourcesDirectory;
153
154 @Parameter( defaultValue = "${project.compileClasspathElements}", readonly = true )
155 private List<String> compilePath;
156
157 @Parameter( defaultValue = "${project.testClasspathElements}", readonly = true )
158 private List<String> testPath;
159
160 private LocationManager locationManager = new LocationManager();
161
162 private Map<String, JavaModuleDescriptor> pathElements;
163
164 private Collection<String> classpathElements;
165
166 private Collection<String> modulepathElements;
167
168 public void execute()
169 throws MojoExecutionException, CompilationFailureException
170 {
171 if ( skip )
172 {
173 getLog().info( "Not compiling test sources" );
174 return;
175 }
176 super.execute();
177 }
178
179 protected List<String> getCompileSourceRoots()
180 {
181 return compileSourceRoots;
182 }
183
184 @Override
185 protected Map<String, JavaModuleDescriptor> getPathElements()
186 {
187 return pathElements;
188 }
189
190 protected List<String> getClasspathElements()
191 {
192 return new ArrayList<>( classpathElements );
193 }
194
195 @Override
196 protected List<String> getModulepathElements()
197 {
198 return new ArrayList<>( modulepathElements );
199 }
200
201 protected File getOutputDirectory()
202 {
203 return outputDirectory;
204 }
205
206 @Override
207 protected void preparePaths( Set<File> sourceFiles )
208 {
209 File mainOutputDirectory = new File( getProject().getBuild().getOutputDirectory() );
210
211 boolean hasMainModuleDescriptor = new File( mainOutputDirectory, "module-info.class" ).exists();
212
213 boolean hasTestModuleDescriptor = false;
214
215
216 for ( File sourceFile : sourceFiles )
217 {
218
219 if ( "module-info.java".equals( sourceFile.getName() ) )
220 {
221 hasTestModuleDescriptor = true;
222 break;
223 }
224 }
225
226 if ( release != null )
227 {
228 if ( Integer.valueOf( release ) < 9 )
229 {
230 pathElements = Collections.emptyMap();
231 modulepathElements = Collections.emptyList();
232 classpathElements = testPath;
233 return;
234 }
235 }
236 else if ( Double.valueOf( getTarget() ) < Double.valueOf( MODULE_INFO_TARGET ) )
237 {
238 pathElements = Collections.emptyMap();
239 modulepathElements = Collections.emptyList();
240 classpathElements = testPath;
241 return;
242 }
243
244 if ( hasTestModuleDescriptor )
245 {
246 modulepathElements = testPath;
247 classpathElements = Collections.emptyList();
248
249 if ( hasMainModuleDescriptor )
250 {
251
252 }
253 else
254 {
255
256
257
258
259 throw new UnsupportedOperationException( "Can't compile test sources "
260 + "when main sources are missing a module descriptor" );
261 }
262 }
263 else
264 {
265 if ( hasMainModuleDescriptor )
266 {
267 ResolvePathsResult<String> result;
268
269 try
270 {
271 ResolvePathsRequest<String> request =
272 ResolvePathsRequest.withStrings( testPath )
273 .setMainModuleDescriptor( mainOutputDirectory.getAbsolutePath() );
274
275 Toolchain toolchain = getToolchain();
276 if ( toolchain != null && toolchain instanceof DefaultJavaToolChain )
277 {
278 request.setJdkHome( ( (DefaultJavaToolChain) toolchain ).getJavaHome() );
279 }
280
281 result = locationManager.resolvePaths( request );
282 }
283 catch ( IOException e )
284 {
285 throw new RuntimeException( e );
286 }
287
288 JavaModuleDescriptor moduleDescriptor = result.getMainModuleDescriptor();
289
290 pathElements = new LinkedHashMap<String, JavaModuleDescriptor>( result.getPathElements().size() );
291 pathElements.putAll( result.getPathElements() );
292
293 modulepathElements = result.getModulepathElements().keySet();
294 classpathElements = result.getClasspathElements();
295
296 if ( compilerArgs == null )
297 {
298 compilerArgs = new ArrayList<String>();
299 }
300 compilerArgs.add( "--patch-module" );
301
302 StringBuilder patchModuleValue = new StringBuilder( moduleDescriptor.name() )
303 .append( '=' )
304 .append( mainOutputDirectory )
305 .append( PS );
306 for ( String root : compileSourceRoots )
307 {
308 patchModuleValue.append( root ).append( PS );
309 }
310
311 compilerArgs.add( patchModuleValue.toString() );
312
313 compilerArgs.add( "--add-reads" );
314 compilerArgs.add( moduleDescriptor.name() + "=ALL-UNNAMED" );
315 }
316 else
317 {
318 modulepathElements = Collections.emptyList();
319 classpathElements = testPath;
320 }
321 }
322 }
323
324 protected SourceInclusionScanner getSourceInclusionScanner( int staleMillis )
325 {
326 SourceInclusionScanner scanner;
327
328 if ( testIncludes.isEmpty() && testExcludes.isEmpty() )
329 {
330 scanner = new StaleSourceScanner( staleMillis );
331 }
332 else
333 {
334 if ( testIncludes.isEmpty() )
335 {
336 testIncludes.add( "**/*.java" );
337 }
338 scanner = new StaleSourceScanner( staleMillis, testIncludes, testExcludes );
339 }
340
341 return scanner;
342 }
343
344 protected SourceInclusionScanner getSourceInclusionScanner( String inputFileEnding )
345 {
346 SourceInclusionScanner scanner;
347
348
349 String defaultIncludePattern = "**/*" + ( inputFileEnding.startsWith( "." ) ? "" : "." ) + inputFileEnding;
350
351 if ( testIncludes.isEmpty() && testExcludes.isEmpty() )
352 {
353 testIncludes = Collections.singleton( defaultIncludePattern );
354 scanner = new SimpleSourceInclusionScanner( testIncludes, Collections.<String>emptySet() );
355 }
356 else
357 {
358 if ( testIncludes.isEmpty() )
359 {
360 testIncludes.add( defaultIncludePattern );
361 }
362 scanner = new SimpleSourceInclusionScanner( testIncludes, testExcludes );
363 }
364
365 return scanner;
366 }
367
368 protected String getSource()
369 {
370 return testSource == null ? source : testSource;
371 }
372
373 protected String getTarget()
374 {
375 return testTarget == null ? target : testTarget;
376 }
377
378 @Override
379 protected String getRelease()
380 {
381 return testRelease == null ? release : testRelease;
382 }
383
384 protected String getCompilerArgument()
385 {
386 return testCompilerArgument == null ? compilerArgument : testCompilerArgument;
387 }
388
389 protected Map<String, String> getCompilerArguments()
390 {
391 return testCompilerArguments == null ? compilerArguments : testCompilerArguments;
392 }
393
394 protected File getGeneratedSourcesDirectory()
395 {
396 return generatedTestSourcesDirectory;
397 }
398
399 @Override
400 protected boolean isTestCompile()
401 {
402 return true;
403 }
404
405 }