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.groovyworkarounds.DotGroovyFile;
21 import org.codehaus.gmavenplus.model.IncludeClasspath;
22 import org.codehaus.gmavenplus.model.internal.Version;
23 import org.codehaus.gmavenplus.util.FileUtils;
24
25 import java.io.File;
26 import java.lang.reflect.InvocationTargetException;
27 import java.lang.reflect.Method;
28 import java.net.MalformedURLException;
29 import java.util.HashMap;
30 import java.util.HashSet;
31 import java.util.List;
32 import java.util.Map;
33 import java.util.Set;
34
35 import static org.codehaus.gmavenplus.util.ReflectionUtils.findConstructor;
36 import static org.codehaus.gmavenplus.util.ReflectionUtils.findMethod;
37 import static org.codehaus.gmavenplus.util.ReflectionUtils.invokeConstructor;
38 import static org.codehaus.gmavenplus.util.ReflectionUtils.invokeMethod;
39
40
41
42
43
44
45
46
47 public abstract class AbstractGenerateStubsMojo extends AbstractGroovyStubSourcesMojo {
48
49
50
51
52 protected static final Version GROOVY_5_0_0_ALPHA13 = new Version(5, 0, 0, "alpha-13");
53
54
55
56
57 protected static final Version GROOVY_5_0_0_ALPHA11 = new Version(5, 0, 0, "alpha-11");
58
59
60
61
62 protected static final Version GROOVY_5_0_0_ALPHA8 = new Version(5, 0, 0, "alpha-8");
63
64
65
66
67 protected static final Version GROOVY_5_0_0_ALPHA3 = new Version(5, 0, 0, "alpha-3");
68
69
70
71
72 protected static final Version GROOVY_5_0_0_ALPHA1 = new Version(5, 0, 0, "alpha-1");
73
74
75
76
77 protected static final Version GROOVY_4_0_27 = new Version(4, 0, 27);
78
79
80
81
82 protected static final Version GROOVY_4_0_24 = new Version(4, 0, 24);
83
84
85
86
87 protected static final Version GROOVY_4_0_21 = new Version(4, 0, 21);
88
89
90
91
92 protected static final Version GROOVY_4_0_16 = new Version(4, 0, 16);
93
94
95
96
97 protected static final Version GROOVY_4_0_11 = new Version(4, 0, 11);
98
99
100
101
102 protected static final Version GROOVY_4_0_6 = new Version(4, 0, 6);
103
104
105
106
107 protected static final Version GROOVY_4_0_2 = new Version(4, 0, 2);
108
109
110
111
112 protected static final Version GROOVY_4_0_0_BETA1 = new Version(4, 0, 0, "beta-1");
113
114
115
116
117 protected static final Version GROOVY_4_0_0_ALPHA3 = new Version(4, 0, 0, "alpha-3");
118
119
120
121
122 protected static final Version GROOVY_4_0_0_ALPHA1 = new Version(4, 0, 0, "alpha-1");
123
124
125
126
127 protected static final Version GROOVY_3_0_8 = new Version(3, 0, 8);
128
129
130
131
132 protected static final Version GROOVY_3_0_6 = new Version(3, 0, 6);
133
134
135
136
137 protected static final Version GROOVY_3_0_3 = new Version(3, 0, 3);
138
139
140
141
142 protected static final Version GROOVY_3_0_0_BETA2 = new Version(3, 0, 0, "beta-2");
143
144
145
146
147 protected static final Version GROOVY_3_0_0_BETA1 = new Version(3, 0, 0, "beta-1");
148
149
150
151
152 protected static final Version GROOVY_3_0_0_ALPHA4 = new Version(3, 0, 0, "alpha-4");
153
154
155
156
157 protected static final Version GROOVY_3_0_0_ALPHA2 = new Version(3, 0, 0, "alpha-2");
158
159
160
161
162 protected static final Version GROOVY_3_0_0_ALPHA1 = new Version(3, 0, 0, "alpha-1");
163
164
165
166
167 protected static final Version GROOVY_2_6_0_ALPHA4 = new Version(2, 6, 0, "alpha-4");
168
169
170
171
172 protected static final Version GROOVY_2_6_0_ALPHA1 = new Version(2, 6, 0, "alpha-1");
173
174
175
176
177 protected static final Version GROOVY_2_5_7 = new Version(2, 5, 7);
178
179
180
181
182 protected static final Version GROOVY_2_5_3 = new Version(2, 5, 3);
183
184
185
186
187 protected static final Version GROOVY_2_3_3 = new Version(2, 3, 3);
188
189
190
191
192 protected static final Version GROOVY_2_1_3 = new Version(2, 1, 3);
193
194
195
196
197 protected static final Version GROOVY_1_9_0_BETA1 = new Version(1, 9, 0, "beta-1");
198
199
200
201
202 protected static final Version GROOVY_1_9_0_BETA3 = new Version(1, 9, 0, "beta-3");
203
204
205
206
207 protected static final Version GROOVY_1_8_2 = new Version(1, 8, 2);
208
209
210
211
212 protected static final Version GROOVY_1_8_3 = new Version(1, 8, 3);
213
214
215
216
217 @Parameter(defaultValue = "${project.build.sourceEncoding}")
218 protected String sourceEncoding;
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267 @Parameter(property = "maven.compiler.target", defaultValue = "1.8")
268 protected String targetBytecode;
269
270
271
272
273
274
275 @Parameter(property = "skipBytecodeCheck", defaultValue = "false")
276 protected boolean skipBytecodeCheck;
277
278
279
280
281 @Parameter(defaultValue = "false")
282 protected boolean debug;
283
284
285
286
287 @Parameter(defaultValue = "false")
288 protected boolean verbose;
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303 @Parameter(defaultValue = "1")
304 protected int warningLevel;
305
306
307
308
309 @Parameter(defaultValue = "0")
310 protected int tolerance;
311
312
313
314
315
316
317
318
319
320
321
322
323 @Parameter(defaultValue = "PROJECT_ONLY")
324 protected IncludeClasspath includeClasspath;
325
326
327
328
329
330
331
332
333
334
335
336
337
338 protected synchronized void doStubGeneration(final Set<File> stubSources, final List<?> classpath, final File outputDirectory) throws ClassNotFoundException, InvocationTargetException, IllegalAccessException, InstantiationException, MalformedURLException {
339 if (stubSources == null || stubSources.isEmpty()) {
340 getLog().info("No sources specified for stub generation. Skipping.");
341 return;
342 }
343
344 setupClassWrangler(classpath, includeClasspath);
345
346 logPluginClasspath();
347 classWrangler.logGroovyVersion(mojoExecution.getMojoDescriptor().getGoal());
348
349 if (!groovyVersionSupportsAction()) {
350 getLog().error("Your Groovy version (" + classWrangler.getGroovyVersionString() + ") doesn't support stub generation. The minimum version of Groovy required is " + minGroovyVersion + ". Skipping stub generation.");
351 return;
352 }
353
354 if (!skipBytecodeCheck) {
355 verifyGroovyVersionSupportsTargetBytecode();
356 }
357
358
359 Class<?> compilerConfigurationClass = classWrangler.getClass("org.codehaus.groovy.control.CompilerConfiguration");
360 Class<?> javaStubCompilationUnitClass = classWrangler.getClass("org.codehaus.groovy.tools.javac.JavaStubCompilationUnit");
361 Class<?> groovyClassLoaderClass = classWrangler.getClass("groovy.lang.GroovyClassLoader");
362
363
364 Object compilerConfiguration = setupCompilerConfiguration(outputDirectory, compilerConfigurationClass);
365 Object groovyClassLoader = invokeConstructor(findConstructor(groovyClassLoaderClass, ClassLoader.class, compilerConfigurationClass), classWrangler.getClassLoader(), compilerConfiguration);
366 Object javaStubCompilationUnit = invokeConstructor(findConstructor(javaStubCompilationUnitClass, compilerConfigurationClass, groovyClassLoaderClass, File.class), compilerConfiguration, groovyClassLoader, outputDirectory);
367
368
369 addGroovySources(stubSources, compilerConfigurationClass, javaStubCompilationUnitClass, compilerConfiguration, javaStubCompilationUnit);
370
371
372 invokeMethod(findMethod(javaStubCompilationUnitClass, "compile"), javaStubCompilationUnit);
373 }
374
375
376
377
378
379
380
381
382
383
384
385 protected Object setupCompilerConfiguration(final File outputDirectory, final Class<?> compilerConfigurationClass) throws InvocationTargetException, IllegalAccessException, InstantiationException {
386 Object compilerConfiguration = invokeConstructor(findConstructor(compilerConfigurationClass));
387 invokeMethod(findMethod(compilerConfigurationClass, "setDebug", boolean.class), compilerConfiguration, debug);
388 invokeMethod(findMethod(compilerConfigurationClass, "setVerbose", boolean.class), compilerConfiguration, verbose);
389 invokeMethod(findMethod(compilerConfigurationClass, "setWarningLevel", int.class), compilerConfiguration, warningLevel);
390 invokeMethod(findMethod(compilerConfigurationClass, "setTolerance", int.class), compilerConfiguration, tolerance);
391 invokeMethod(findMethod(compilerConfigurationClass, "setTargetBytecode", String.class), compilerConfiguration, translateJavacTargetToTargetBytecode(targetBytecode));
392 if (sourceEncoding != null) {
393 invokeMethod(findMethod(compilerConfigurationClass, "setSourceEncoding", String.class), compilerConfiguration, sourceEncoding);
394 }
395 Map<String, Object> options = new HashMap<>();
396 options.put("stubDir", outputDirectory);
397 options.put("keepStubs", Boolean.TRUE);
398 invokeMethod(findMethod(compilerConfigurationClass, "setJointCompilationOptions", Map.class), compilerConfiguration, options);
399
400 return compilerConfiguration;
401 }
402
403
404
405
406
407
408
409
410
411
412
413
414 protected void addGroovySources(final Set<File> stubSources, final Class<?> compilerConfigurationClass, final Class<?> javaStubCompilationUnitClass, final Object compilerConfiguration, final Object javaStubCompilationUnit) throws InvocationTargetException, IllegalAccessException {
415 Set<String> scriptExtensions = new HashSet<>();
416 for (File stubSource : stubSources) {
417 scriptExtensions.add(FileUtils.getFileExtension(stubSource));
418 }
419 getLog().debug("Detected Groovy file extensions: " + scriptExtensions + ".");
420 if (supportsSettingExtensions()) {
421 invokeMethod(findMethod(compilerConfigurationClass, "setScriptExtensions", Set.class), compilerConfiguration, scriptExtensions);
422 }
423 getLog().debug("Adding Groovy to generate stubs for:");
424 Method addSource = findMethod(javaStubCompilationUnitClass, "addSource", File.class);
425 for (File stubSource : stubSources) {
426 getLog().debug(" " + stubSource);
427 if (supportsSettingExtensions()) {
428 invokeMethod(addSource, javaStubCompilationUnit, stubSource);
429 } else {
430 DotGroovyFile dotGroovyFile = new DotGroovyFile(stubSource).setScriptExtensions(scriptExtensions);
431 invokeMethod(addSource, javaStubCompilationUnit, dotGroovyFile);
432 }
433 }
434 }
435
436
437
438
439
440
441 protected boolean supportsSettingExtensions() {
442 return groovyAtLeast(GROOVY_1_8_3) && (groovyOlderThan(GROOVY_1_9_0_BETA1) || groovyNewerThan(GROOVY_1_9_0_BETA3));
443 }
444
445
446
447
448
449
450 protected void logGeneratedStubs(File outputDirectory) {
451 Set<File> stubs = getStubs(outputDirectory);
452 getLog().info("Generated " + stubs.size() + " stub" + (stubs.size() != 1 ? "s" : "") + ".");
453 }
454
455
456
457
458
459
460
461
462
463 protected void resetStubModifiedDates(final Set<File> stubs) {
464 for (File stub : stubs) {
465 boolean success = stub.setLastModified(0L);
466 if (!success) {
467 getLog().warn("Unable to set modified time on stub " + stub.getAbsolutePath() + ".");
468 }
469 }
470 }
471
472
473
474
475
476
477 protected void verifyGroovyVersionSupportsTargetBytecode() {
478 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)) {
479 if (groovyNewerThan(GROOVY_5_0_0_ALPHA1)) {
480 throw new IllegalArgumentException("Target bytecode " + targetBytecode + " isn't accepted by Groovy " + GROOVY_5_0_0_ALPHA1 + " or newer.");
481 }
482 }
483
484 if ("25".equals(targetBytecode)) {
485 if (groovyOlderThan(GROOVY_4_0_27)) {
486 throw new IllegalArgumentException("Target bytecode " + targetBytecode + " requires Groovy " + GROOVY_4_0_24 + " or newer.");
487 }
488 if (groovyNewerThan(GROOVY_5_0_0_ALPHA1) && groovyOlderThan(GROOVY_5_0_0_ALPHA13)) {
489 throw new IllegalArgumentException("Target bytecode " + targetBytecode + " requires Groovy " + GROOVY_5_0_0_ALPHA13 + " or newer.");
490 }
491 } else if ("24".equals(targetBytecode)) {
492 if (groovyOlderThan(GROOVY_4_0_24)) {
493 throw new IllegalArgumentException("Target bytecode " + targetBytecode + " requires Groovy " + GROOVY_4_0_24 + " or newer.");
494 }
495 if (groovyNewerThan(GROOVY_5_0_0_ALPHA1) && groovyOlderThan(GROOVY_5_0_0_ALPHA11)) {
496 throw new IllegalArgumentException("Target bytecode " + targetBytecode + " requires Groovy " + GROOVY_5_0_0_ALPHA11 + " or newer.");
497 }
498 } else if ("23".equals(targetBytecode)) {
499 if (groovyOlderThan(GROOVY_4_0_21)) {
500 throw new IllegalArgumentException("Target bytecode " + targetBytecode + " requires Groovy " + GROOVY_4_0_21 + " or newer.");
501 }
502 if (groovyNewerThan(GROOVY_5_0_0_ALPHA1) && groovyOlderThan(GROOVY_5_0_0_ALPHA8)) {
503 throw new IllegalArgumentException("Target bytecode " + targetBytecode + " requires Groovy " + GROOVY_5_0_0_ALPHA8 + " or newer.");
504 }
505 } else if ("22".equals(targetBytecode)) {
506 if (groovyOlderThan(GROOVY_4_0_16)) {
507 throw new IllegalArgumentException("Target bytecode " + targetBytecode + " requires Groovy " + GROOVY_4_0_16 + " or newer.");
508 }
509 if (groovyNewerThan(GROOVY_5_0_0_ALPHA1) && groovyOlderThan(GROOVY_5_0_0_ALPHA3)) {
510 throw new IllegalArgumentException("Target bytecode " + targetBytecode + " requires Groovy " + GROOVY_5_0_0_ALPHA3 + " or newer.");
511 }
512 } else 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 return AbstractCompileMojo.translateJavacTargetToTargetBytecode(targetBytecode);
575 }
576
577 }