1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.codehaus.gmavenplus.mojo;
18
19 import org.apache.maven.plugins.annotations.Parameter;
20 import org.codehaus.gmavenplus.model.IncludeClasspath;
21 import org.codehaus.gmavenplus.model.internal.Version;
22
23 import java.io.File;
24 import java.lang.reflect.InvocationTargetException;
25 import java.lang.reflect.Method;
26 import java.net.MalformedURLException;
27 import java.security.CodeSource;
28 import java.util.HashMap;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.Set;
32
33 import static org.codehaus.gmavenplus.util.ReflectionUtils.findConstructor;
34 import static org.codehaus.gmavenplus.util.ReflectionUtils.findMethod;
35 import static org.codehaus.gmavenplus.util.ReflectionUtils.invokeConstructor;
36 import static org.codehaus.gmavenplus.util.ReflectionUtils.invokeMethod;
37
38
39
40
41
42
43
44
45 public abstract class AbstractCompileMojo extends AbstractGroovySourcesMojo {
46
47
48
49
50 protected static final Version GROOVY_5_0_0_ALPHA1 = new Version(5, 0, 0, "alpha-1");
51
52
53
54
55 protected static final Version GROOVY_4_0_11 = new Version(4, 0, 11);
56
57
58
59
60 protected static final Version GROOVY_4_0_6 = new Version(4, 0, 6);
61
62
63
64
65 protected static final Version GROOVY_4_0_2 = new Version(4, 0, 2);
66
67
68
69
70 protected static final Version GROOVY_4_0_0_BETA1 = new Version(4, 0, 0, "beta-1");
71
72
73
74
75 protected static final Version GROOVY_4_0_0_ALPHA3 = new Version(4, 0, 0, "alpha-3");
76
77
78
79
80 protected static final Version GROOVY_4_0_0_ALPHA1 = new Version(4, 0, 0, "alpha-1");
81
82
83
84
85 protected static final Version GROOVY_3_0_8 = new Version(3, 0, 8);
86
87
88
89
90 protected static final Version GROOVY_3_0_6 = new Version(3, 0, 6);
91
92
93
94
95 protected static final Version GROOVY_3_0_5 = new Version(3, 0, 5);
96
97
98
99
100 protected static final Version GROOVY_3_0_3 = new Version(3, 0, 3);
101
102
103
104
105 protected static final Version GROOVY_3_0_0_BETA2 = new Version(3, 0, 0, "beta-2");
106
107
108
109
110 protected static final Version GROOVY_3_0_0_BETA1 = new Version(3, 0, 0, "beta-1");
111
112
113
114
115 protected static final Version GROOVY_3_0_0_ALPHA4 = new Version(3, 0, 0, "alpha-4");
116
117
118
119
120 protected static final Version GROOVY_3_0_0_ALPHA2 = new Version(3, 0, 0, "alpha-2");
121
122
123
124
125 protected static final Version GROOVY_3_0_0_ALPHA1 = new Version(3, 0, 0, "alpha-1");
126
127
128
129
130 protected static final Version GROOVY_2_6_0_ALPHA4 = new Version(2, 6, 0, "alpha-4");
131
132
133
134
135 protected static final Version GROOVY_2_6_0_ALPHA1 = new Version(2, 6, 0, "alpha-1");
136
137
138
139
140 protected static final Version GROOVY_2_5_7 = new Version(2, 5, 7);
141
142
143
144
145 protected static final Version GROOVY_2_5_3 = new Version(2, 5, 3);
146
147
148
149
150 protected static final Version GROOVY_2_5_0_ALPHA1 = new Version(2, 5, 0, "alpha-1");
151
152
153
154
155 protected static final Version GROOVY_2_3_3 = new Version(2, 3, 3);
156
157
158
159
160 protected static final Version GROOVY_2_1_3 = new Version(2, 1, 3);
161
162
163
164
165 protected static final Version GROOVY_2_1_0_BETA1 = new Version(2, 1, 0, "beta-1");
166
167
168
169
170 protected static final Version GROOVY_2_0_0_BETA3 = new Version(2, 0, 0, "beta-3");
171
172
173
174
175 protected static final Version GROOVY_1_6_0 = new Version(1, 6, 0);
176
177
178
179
180 @Parameter(defaultValue = "${project.build.sourceEncoding}")
181 protected String sourceEncoding;
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217 @Parameter(property = "maven.compiler.target", defaultValue = "1.8")
218 protected String targetBytecode;
219
220
221
222
223
224
225 @Parameter(property = "skipBytecodeCheck", defaultValue = "false")
226 protected boolean skipBytecodeCheck;
227
228
229
230
231 @Parameter(defaultValue = "false")
232 protected boolean debug;
233
234
235
236
237 @Parameter(defaultValue = "false")
238 protected boolean verbose;
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253 @Parameter(defaultValue = "1")
254 protected int warningLevel;
255
256
257
258
259 @Parameter(defaultValue = "0")
260 protected int tolerance;
261
262
263
264
265
266 @Parameter(defaultValue = "false")
267 protected boolean invokeDynamic;
268
269
270
271
272
273
274
275 @Parameter
276 protected Boolean parallelParsing = null;
277
278
279
280
281
282 @Parameter
283 protected File configScript;
284
285
286
287
288
289 @Parameter(defaultValue = "false")
290 protected boolean parameters;
291
292
293
294
295
296
297
298
299
300
301
302
303 @Parameter(defaultValue = "PROJECT_ONLY")
304 protected IncludeClasspath includeClasspath;
305
306
307
308
309
310
311
312 @Parameter(defaultValue = "false")
313 protected boolean previewFeatures;
314
315
316
317
318
319
320
321
322
323
324
325
326
327 @SuppressWarnings({"rawtypes"})
328 protected synchronized void doCompile(final Set<File> sources, final List classpath, final File compileOutputDirectory)
329 throws ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException, MalformedURLException {
330 if (sources == null || sources.isEmpty()) {
331 getLog().info("No sources specified for compilation. Skipping.");
332 return;
333 }
334
335 setupClassWrangler(classpath, includeClasspath);
336
337 logPluginClasspath();
338 classWrangler.logGroovyVersion(mojoExecution.getMojoDescriptor().getGoal());
339
340 if (!groovyVersionSupportsAction()) {
341 getLog().error("Your Groovy version (" + classWrangler.getGroovyVersionString() + ") doesn't support compilation. The minimum version of Groovy required is " + minGroovyVersion + ". Skipping compiling.");
342 return;
343 }
344
345 if (!skipBytecodeCheck) {
346 verifyGroovyVersionSupportsTargetBytecode();
347 }
348
349
350 Class<?> compilerConfigurationClass = classWrangler.getClass("org.codehaus.groovy.control.CompilerConfiguration");
351 Class<?> compilationUnitClass = classWrangler.getClass("org.codehaus.groovy.control.CompilationUnit");
352 Class<?> groovyClassLoaderClass = classWrangler.getClass("groovy.lang.GroovyClassLoader");
353
354
355 Object compilerConfiguration = setupCompilerConfiguration(compileOutputDirectory, compilerConfigurationClass);
356 Object groovyClassLoader = invokeConstructor(findConstructor(groovyClassLoaderClass, ClassLoader.class, compilerConfigurationClass), classWrangler.getClassLoader(), compilerConfiguration);
357 Object transformLoader = invokeConstructor(findConstructor(groovyClassLoaderClass, ClassLoader.class), classWrangler.getClassLoader());
358
359
360 Object compilationUnit = setupCompilationUnit(sources, compilerConfigurationClass, compilationUnitClass, groovyClassLoaderClass, compilerConfiguration, groovyClassLoader, transformLoader);
361
362
363 invokeMethod(findMethod(compilationUnitClass, "compile"), compilationUnit);
364
365
366 List classes = (List) invokeMethod(findMethod(compilationUnitClass, "getClasses"), compilationUnit);
367 getLog().info("Compiled " + classes.size() + " file" + (classes.size() != 1 ? "s" : "") + ".");
368 }
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385 protected Object setupCompilationUnit(final Set<File> sources, final Class<?> compilerConfigurationClass, final Class<?> compilationUnitClass, final Class<?> groovyClassLoaderClass, final Object compilerConfiguration, final Object groovyClassLoader, final Object transformLoader) throws InvocationTargetException, IllegalAccessException, InstantiationException {
386 Object compilationUnit;
387 if (groovyAtLeast(GROOVY_1_6_0)) {
388 compilationUnit = invokeConstructor(findConstructor(compilationUnitClass, compilerConfigurationClass, CodeSource.class, groovyClassLoaderClass, groovyClassLoaderClass), compilerConfiguration, null, groovyClassLoader, transformLoader);
389 } else {
390 compilationUnit = invokeConstructor(findConstructor(compilationUnitClass, compilerConfigurationClass, CodeSource.class, groovyClassLoaderClass), compilerConfiguration, null, groovyClassLoader);
391 }
392 getLog().debug("Adding Groovy to compile:");
393 Method addSourceMethod = findMethod(compilationUnitClass, "addSource", File.class);
394 for (File source : sources) {
395 getLog().debug(" " + source);
396 invokeMethod(addSourceMethod, compilationUnit, source);
397 }
398
399 return compilationUnit;
400 }
401
402
403
404
405
406
407
408
409
410
411
412
413 @SuppressWarnings({"rawtypes", "unchecked"})
414 protected Object setupCompilerConfiguration(final File compileOutputDirectory, final Class<?> compilerConfigurationClass) throws InvocationTargetException, IllegalAccessException, InstantiationException, ClassNotFoundException {
415 Object compilerConfiguration = invokeConstructor(findConstructor(compilerConfigurationClass));
416 if (configScript != null) {
417 if (!configScript.exists()) {
418 getLog().warn("Configuration script file (" + configScript.getAbsolutePath() + ") doesn't exist. Ignoring configScript parameter.");
419 } else if (groovyOlderThan(GROOVY_2_1_0_BETA1)) {
420 getLog().warn("Requested to use configScript, but your Groovy version (" + classWrangler.getGroovyVersionString() + ") doesn't support it (must be " + GROOVY_2_1_0_BETA1 + " or newer). Ignoring configScript parameter.");
421 } else {
422 Class<?> bindingClass = classWrangler.getClass("groovy.lang.Binding");
423 Class<?> importCustomizerClass = classWrangler.getClass("org.codehaus.groovy.control.customizers.ImportCustomizer");
424 Class<?> groovyShellClass = classWrangler.getClass("groovy.lang.GroovyShell");
425
426 Object binding = invokeConstructor(findConstructor(bindingClass));
427 invokeMethod(findMethod(bindingClass, "setVariable", String.class, Object.class), binding, "configuration", compilerConfiguration);
428 Object shellCompilerConfiguration = invokeConstructor(findConstructor(compilerConfigurationClass));
429 Object importCustomizer = invokeConstructor(findConstructor(importCustomizerClass));
430 invokeMethod(findMethod(importCustomizerClass, "addStaticStar", String.class), importCustomizer, "org.codehaus.groovy.control.customizers.builder.CompilerCustomizationBuilder");
431 List compilationCustomizers = (List) invokeMethod(findMethod(compilerConfigurationClass, "getCompilationCustomizers"), shellCompilerConfiguration);
432 compilationCustomizers.add(importCustomizer);
433 Object shell = invokeConstructor(findConstructor(groovyShellClass, ClassLoader.class, bindingClass, compilerConfigurationClass), classWrangler.getClassLoader(), binding, shellCompilerConfiguration);
434 getLog().debug("Using configuration script " + configScript + " for compilation.");
435 invokeMethod(findMethod(groovyShellClass, "evaluate", File.class), shell, configScript);
436 }
437 }
438 invokeMethod(findMethod(compilerConfigurationClass, "setDebug", boolean.class), compilerConfiguration, debug);
439 invokeMethod(findMethod(compilerConfigurationClass, "setVerbose", boolean.class), compilerConfiguration, verbose);
440 invokeMethod(findMethod(compilerConfigurationClass, "setWarningLevel", int.class), compilerConfiguration, warningLevel);
441 invokeMethod(findMethod(compilerConfigurationClass, "setTolerance", int.class), compilerConfiguration, tolerance);
442 invokeMethod(findMethod(compilerConfigurationClass, "setTargetBytecode", String.class), compilerConfiguration, translateJavacTargetToTargetBytecode(targetBytecode));
443 if (previewFeatures) {
444 if (isJavaSupportPreviewFeatures()) {
445 if (groovyOlderThan(GROOVY_2_5_7) || (groovyAtLeast(GROOVY_2_6_0_ALPHA1) && groovyOlderThan(GROOVY_3_0_0_BETA1))) {
446 getLog().warn("Requested to use preview features, but your Groovy version (" + classWrangler.getGroovyVersionString() + ") doesn't support it (must be " + GROOVY_2_5_7 + "/" + GROOVY_3_0_0_BETA1 + " or newer. No 2.6 version is supported. Ignoring previewFeatures parameter.");
447 } else {
448 invokeMethod(findMethod(compilerConfigurationClass, "setPreviewFeatures", boolean.class), compilerConfiguration, previewFeatures);
449 }
450 } else {
451 getLog().warn("Requested to use to use preview features, but your Java version (" + getJavaVersionString() + ") doesn't support it. Ignoring previewFeatures parameter.");
452 }
453 }
454 if (sourceEncoding != null) {
455 invokeMethod(findMethod(compilerConfigurationClass, "setSourceEncoding", String.class), compilerConfiguration, sourceEncoding);
456 }
457 invokeMethod(findMethod(compilerConfigurationClass, "setTargetDirectory", String.class), compilerConfiguration, compileOutputDirectory.getAbsolutePath());
458 if (invokeDynamic || groovyAtLeast(GROOVY_4_0_0_ALPHA1)) {
459 if (groovyAtLeast(GROOVY_2_0_0_BETA3)) {
460 if (classWrangler.isGroovyIndy()) {
461 if (isJavaSupportIndy()) {
462 Map<String, Boolean> optimizationOptions = (Map<String, Boolean>) invokeMethod(findMethod(compilerConfigurationClass, "getOptimizationOptions"), compilerConfiguration);
463 optimizationOptions.put("indy", true);
464 optimizationOptions.put("int", false);
465 getLog().info("invokedynamic enabled.");
466 } else {
467 getLog().warn("Requested to use to use invokedynamic, but your Java version (" + getJavaVersionString() + ") doesn't support it. Ignoring invokeDynamic parameter.");
468 }
469 } else {
470 getLog().warn("Requested to use invokedynamic, but your Groovy version doesn't support it (must use have indy classifier). Ignoring invokeDynamic parameter.");
471 }
472 } else {
473 getLog().warn("Requested to use invokeDynamic, but your Groovy version (" + classWrangler.getGroovyVersionString() + ") doesn't support it (must be " + GROOVY_2_0_0_BETA3 + " or newer). Ignoring invokeDynamic parameter.");
474 }
475 }
476 if (parameters) {
477 if (groovyAtLeast(GROOVY_2_5_0_ALPHA1)) {
478 if (isJavaSupportParameters()) {
479 invokeMethod(findMethod(compilerConfigurationClass, "setParameters", boolean.class), compilerConfiguration, parameters);
480 } else {
481 getLog().warn("Requested to use to use parameters, but your Java version (" + getJavaVersionString() + ") doesn't support it. Ignoring parameters parameter.");
482 }
483 } else {
484 getLog().warn("Requested to use parameters, but your Groovy version (" + classWrangler.getGroovyVersionString() + ") doesn't support it (must be " + GROOVY_2_5_0_ALPHA1 + " or newer). Ignoring parameters parameter.");
485 }
486 }
487 if (groovyAtLeast(GROOVY_3_0_5)) {
488 if ((parallelParsing == null && groovyAtLeast(GROOVY_4_0_0_ALPHA1)) || (parallelParsing != null && parallelParsing)) {
489 Map<String, Boolean> optimizationOptions = (Map<String, Boolean>) invokeMethod(findMethod(compilerConfigurationClass, "getOptimizationOptions"), compilerConfiguration);
490 optimizationOptions.put("parallelParse", true);
491 getLog().info("Parallel parsing enabled.");
492 } else {
493 getLog().info("Parallel parsing disabled.");
494 }
495 }
496
497 return compilerConfiguration;
498 }
499
500
501
502
503
504
505 protected void verifyGroovyVersionSupportsTargetBytecode() {
506 if ("1.5".equals(targetBytecode) || "5".equals(targetBytecode) || "1.6".equals(targetBytecode) || "6".equals(targetBytecode) || "1.7".equals(targetBytecode) || "7".equals(targetBytecode) || "1.8".equals(targetBytecode) || "8".equals(targetBytecode) || "1.9".equals(targetBytecode) || "9".equals(targetBytecode) || "10".equals(targetBytecode)) {
507 if (groovyNewerThan(GROOVY_5_0_0_ALPHA1)) {
508 throw new IllegalArgumentException("Target bytecode " + targetBytecode + " isn't accepted by Groovy " + GROOVY_5_0_0_ALPHA1 + " or newer.");
509 }
510 }
511
512 if ("21".equals(targetBytecode)) {
513 if (groovyOlderThan(GROOVY_4_0_11)) {
514 throw new IllegalArgumentException("Target bytecode " + targetBytecode + " requires Groovy " + GROOVY_4_0_11 + " or newer.");
515 }
516 } else if ("20".equals(targetBytecode)) {
517 if (groovyOlderThan(GROOVY_4_0_6)) {
518 throw new IllegalArgumentException("Target bytecode " + targetBytecode + " requires Groovy " + GROOVY_4_0_6 + " or newer.");
519 }
520 } else if ("19".equals(targetBytecode)) {
521 if (groovyOlderThan(GROOVY_4_0_2)) {
522 throw new IllegalArgumentException("Target bytecode " + targetBytecode + " requires Groovy " + GROOVY_4_0_2 + " or newer.");
523 }
524 } else if ("18".equals(targetBytecode)) {
525 if (groovyOlderThan(GROOVY_4_0_0_BETA1)) {
526 throw new IllegalArgumentException("Target bytecode " + targetBytecode + " requires Groovy " + GROOVY_4_0_0_BETA1 + " or newer.");
527 }
528 } else if ("17".equals(targetBytecode)) {
529 if (groovyOlderThan(GROOVY_3_0_8) || (groovyAtLeast(GROOVY_4_0_0_ALPHA1) && groovyOlderThan(GROOVY_4_0_0_ALPHA3))) {
530 throw new IllegalArgumentException("Target bytecode " + targetBytecode + " requires Groovy " + GROOVY_3_0_8 + "/" + GROOVY_4_0_0_ALPHA3 + " or newer.");
531 }
532 } else if ("16".equals(targetBytecode)) {
533 if (groovyOlderThan(GROOVY_3_0_6)) {
534 throw new IllegalArgumentException("Target bytecode " + targetBytecode + " requires Groovy " + GROOVY_3_0_6 + " or newer.");
535 }
536 } else if ("15".equals(targetBytecode)) {
537 if (groovyOlderThan(GROOVY_3_0_3)) {
538 throw new IllegalArgumentException("Target bytecode " + targetBytecode + " requires Groovy " + GROOVY_3_0_3 + " or newer.");
539 }
540 } else if ("14".equals(targetBytecode)) {
541 if (groovyOlderThan(GROOVY_3_0_0_BETA2)) {
542 throw new IllegalArgumentException("Target bytecode " + targetBytecode + " requires Groovy " + GROOVY_3_0_0_BETA2 + " or newer.");
543 }
544 } else if ("13".equals(targetBytecode)) {
545 if (groovyOlderThan(GROOVY_2_5_7) || (groovyAtLeast(GROOVY_2_6_0_ALPHA1) && groovyOlderThan(GROOVY_3_0_0_BETA1))) {
546 throw new IllegalArgumentException("Target bytecode " + targetBytecode + " requires Groovy " + GROOVY_2_5_7 + "/" + GROOVY_3_0_0_BETA1 + " or newer. No 2.6 version is supported.");
547 }
548 } else if ("12".equals(targetBytecode) || "11".equals(targetBytecode) || "10".equals(targetBytecode)) {
549 if (groovyOlderThan(GROOVY_2_5_3) || (groovyAtLeast(GROOVY_2_6_0_ALPHA1) && groovyOlderThan(GROOVY_3_0_0_ALPHA4))) {
550 throw new IllegalArgumentException("Target bytecode " + targetBytecode + " requires Groovy " + GROOVY_2_5_3 + "/" + GROOVY_3_0_0_ALPHA4 + " or newer. No 2.6 version is supported.");
551 }
552 } else if ("9".equals(targetBytecode) || "1.9".equals(targetBytecode)) {
553 if (!isGroovyIndy() && (groovyOlderThan(GROOVY_2_5_3)
554 || (groovyAtLeast(GROOVY_2_6_0_ALPHA1) && groovyOlderThan(GROOVY_2_6_0_ALPHA4))
555 || (groovyAtLeast(GROOVY_3_0_0_ALPHA1) && groovyOlderThan(GROOVY_3_0_0_ALPHA2)))) {
556 throw new IllegalArgumentException("Target bytecode " + targetBytecode + " requires Groovy " + GROOVY_2_5_3 + "/" + GROOVY_2_6_0_ALPHA4 + "/" + GROOVY_3_0_0_ALPHA2 + " or newer.");
557 } else if (isGroovyIndy() && (groovyOlderThan(GROOVY_2_5_3) || (groovyAtLeast(GROOVY_2_6_0_ALPHA1) && groovyOlderThan(GROOVY_3_0_0_ALPHA4)))) {
558 throw new IllegalArgumentException("Target bytecode " + targetBytecode + " requires Groovy " + GROOVY_2_5_3 + "/" + GROOVY_3_0_0_ALPHA4 + " or newer. No 2.6 version is supported.");
559 }
560 } else if ("8".equals(targetBytecode) || "1.8".equals(targetBytecode)) {
561 if (groovyOlderThan(GROOVY_2_3_3)) {
562 throw new IllegalArgumentException("Target bytecode " + targetBytecode + " requires Groovy " + GROOVY_2_3_3 + " or newer.");
563 }
564 } else if ("7".equals(targetBytecode) || "1.7".equals(targetBytecode) || "6".equals(targetBytecode) || "1.6".equals(targetBytecode)) {
565 if (groovyOlderThan(GROOVY_2_1_3)) {
566 throw new IllegalArgumentException("Target bytecode " + targetBytecode + " requires Groovy " + GROOVY_2_1_3 + " or newer.");
567 }
568 } else if (!"5".equals(targetBytecode) && !"1.5".equals(targetBytecode) && !"4".equals(targetBytecode) && !"1.4".equals(targetBytecode)) {
569 throw new IllegalArgumentException("Unrecognized target bytecode: '" + targetBytecode + "'. This check can be skipped with 'skipBytecodeCheck', but this may result in a different target bytecode being used.");
570 }
571 }
572
573 protected static String translateJavacTargetToTargetBytecode(String targetBytecode) {
574 Map<String, String> javacTargetToTargetBytecode = new HashMap<>();
575 javacTargetToTargetBytecode.put("5", "1.5");
576 javacTargetToTargetBytecode.put("6", "1.6");
577 javacTargetToTargetBytecode.put("7", "1.7");
578 javacTargetToTargetBytecode.put("8", "1.8");
579 javacTargetToTargetBytecode.put("1.9", "9");
580 return javacTargetToTargetBytecode.getOrDefault(targetBytecode, targetBytecode);
581 }
582
583 }