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