1 package org.codehaus.gmavenplus.util;
2
3 import org.apache.maven.plugin.logging.Log;
4 import org.codehaus.gmavenplus.model.GroovyCompileConfiguration;
5 import org.codehaus.gmavenplus.model.GroovyDocConfiguration;
6 import org.codehaus.gmavenplus.model.GroovyStubConfiguration;
7 import org.codehaus.gmavenplus.model.Link;
8 import org.apache.maven.shared.model.fileset.FileSet;
9 import org.apache.maven.shared.model.fileset.util.FileSetManager;
10 import org.codehaus.gmavenplus.groovyworkarounds.GroovyDocTemplateInfo;
11 import java.util.ArrayList;
12 import java.util.Properties;
13 import org.codehaus.gmavenplus.model.internal.Version;
14
15 import java.io.File;
16 import java.lang.reflect.InvocationTargetException;
17 import java.lang.reflect.Method;
18 import java.security.CodeSource;
19 import java.util.HashMap;
20 import java.util.List;
21 import java.util.Map;
22 import java.util.Set;
23
24 import static org.codehaus.gmavenplus.util.ReflectionUtils.*;
25
26
27
28
29
30
31 public class GroovyCompiler {
32
33
34
35
36 protected static final Version GROOVY_5_0_0_BETA_1 = new Version(5, 0, 0, "beta-1");
37
38
39
40
41 protected static final Version GROOVY_5_0_0_ALPHA13 = new Version(5, 0, 0, "alpha-13");
42
43
44
45
46 protected static final Version GROOVY_5_0_0_ALPHA11 = new Version(5, 0, 0, "alpha-11");
47
48
49
50
51 protected static final Version GROOVY_5_0_0_ALPHA8 = new Version(5, 0, 0, "alpha-8");
52
53
54
55
56 protected static final Version GROOVY_5_0_0_ALPHA3 = new Version(5, 0, 0, "alpha-3");
57
58
59
60
61 protected static final Version GROOVY_5_0_0_ALPHA1 = new Version(5, 0, 0, "alpha-1");
62
63
64
65
66 protected static final Version GROOVY_4_0_27 = new Version(4, 0, 27);
67
68
69
70
71 protected static final Version GROOVY_4_0_24 = new Version(4, 0, 24);
72
73
74
75
76 protected static final Version GROOVY_4_0_21 = new Version(4, 0, 21);
77
78
79
80
81 protected static final Version GROOVY_4_0_16 = new Version(4, 0, 16);
82
83
84
85
86 protected static final Version GROOVY_4_0_11 = new Version(4, 0, 11);
87
88
89
90
91 protected static final Version GROOVY_4_0_6 = new Version(4, 0, 6);
92
93
94
95
96 protected static final Version GROOVY_4_0_2 = new Version(4, 0, 2);
97
98
99
100
101 protected static final Version GROOVY_4_0_0_BETA1 = new Version(4, 0, 0, "beta-1");
102
103
104
105
106 protected static final Version GROOVY_4_0_0_ALPHA3 = new Version(4, 0, 0, "alpha-3");
107
108
109
110
111 protected static final Version GROOVY_4_0_0_ALPHA1 = new Version(4, 0, 0, "alpha-1");
112
113
114
115
116 protected static final Version GROOVY_3_0_8 = new Version(3, 0, 8);
117
118
119
120
121 protected static final Version GROOVY_3_0_6 = new Version(3, 0, 6);
122
123
124
125
126 protected static final Version GROOVY_3_0_5 = new Version(3, 0, 5);
127
128
129
130
131 protected static final Version GROOVY_3_0_3 = new Version(3, 0, 3);
132
133
134
135
136 protected static final Version GROOVY_3_0_0_BETA2 = new Version(3, 0, 0, "beta-2");
137
138
139
140
141 protected static final Version GROOVY_3_0_0_BETA1 = new Version(3, 0, 0, "beta-1");
142
143
144
145
146 protected static final Version GROOVY_3_0_0_ALPHA4 = new Version(3, 0, 0, "alpha-4");
147
148
149
150
151 protected static final Version GROOVY_3_0_0_ALPHA2 = new Version(3, 0, 0, "alpha-2");
152
153
154
155
156 protected static final Version GROOVY_3_0_0_ALPHA1 = new Version(3, 0, 0, "alpha-1");
157
158
159
160
161 protected static final Version GROOVY_2_6_0_ALPHA4 = new Version(2, 6, 0, "alpha-4");
162
163
164
165
166 protected static final Version GROOVY_2_6_0_ALPHA1 = new Version(2, 6, 0, "alpha-1");
167
168
169
170
171 protected static final Version GROOVY_2_5_7 = new Version(2, 5, 7);
172
173
174
175
176 protected static final Version GROOVY_2_5_3 = new Version(2, 5, 3);
177
178
179
180
181 protected static final Version GROOVY_2_5_0_ALPHA1 = new Version(2, 5, 0, "alpha-1");
182
183
184
185
186 protected static final Version GROOVY_2_3_3 = new Version(2, 3, 3);
187
188
189
190
191 protected static final Version GROOVY_1_8_2 = new Version(1, 8, 2);
192
193
194
195
196 protected static final Version GROOVY_1_8_3 = new Version(1, 8, 3);
197
198
199
200
201 protected static final Version GROOVY_2_1_3 = new Version(2, 1, 3);
202
203
204
205
206 protected static final Version GROOVY_2_1_0_BETA1 = new Version(2, 1, 0, "beta-1");
207
208
209
210
211 protected static final Version GROOVY_2_0_0_BETA3 = new Version(2, 0, 0, "beta-3");
212
213
214
215
216 protected static final Version GROOVY_1_9_0_BETA1 = new Version(1, 9, 0, "beta-1");
217
218
219
220
221 protected static final Version GROOVY_1_9_0_BETA3 = new Version(1, 9, 0, "beta-3");
222
223
224
225
226 protected static final Version GROOVY_1_6_0 = new Version(1, 6, 0);
227
228
229
230
231 protected static final Version GROOVY_1_6_0_RC2 = new Version(1, 6, 0, "RC-2");
232
233
234
235
236 protected static final Version GROOVY_1_5_2 = new Version(1, 5, 2);
237
238
239
240
241 protected static final Version JAVA_1_7 = new Version(1, 7);
242
243
244
245
246 protected static final Version JAVA_1_8 = new Version(1, 8);
247
248
249
250
251 protected static final Version JAVA_12 = new Version(12);
252
253 private final ClassWrangler classWrangler;
254 private final Log log;
255
256 public GroovyCompiler(ClassWrangler classWrangler, Log log) {
257 this.classWrangler = classWrangler;
258 this.log = log;
259 }
260
261 public void compile(GroovyCompileConfiguration configuration) throws ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException {
262 if (configuration.getSources() == null || configuration.getSources().isEmpty()) {
263 log.info("No sources specified for compilation. Skipping.");
264 return;
265 }
266
267 if (!configuration.isSkipBytecodeCheck()) {
268 verifyGroovyVersionSupportsTargetBytecode(configuration.getTargetBytecode());
269 }
270
271
272 Class<?> compilerConfigurationClass = classWrangler.getClass("org.codehaus.groovy.control.CompilerConfiguration");
273 Class<?> compilationUnitClass = classWrangler.getClass("org.codehaus.groovy.control.CompilationUnit");
274 Class<?> groovyClassLoaderClass = classWrangler.getClass("groovy.lang.GroovyClassLoader");
275
276
277 Object compilerConfiguration = setupCompilerConfiguration(configuration, compilerConfigurationClass);
278 Object groovyClassLoader = invokeConstructor(findConstructor(groovyClassLoaderClass, ClassLoader.class, compilerConfigurationClass), classWrangler.getClassLoader(), compilerConfiguration);
279 Object transformLoader = invokeConstructor(findConstructor(groovyClassLoaderClass, ClassLoader.class), classWrangler.getClassLoader());
280
281
282 Object compilationUnit = setupCompilationUnit(configuration.getSources(), compilerConfigurationClass, compilationUnitClass, groovyClassLoaderClass, compilerConfiguration, groovyClassLoader, transformLoader);
283
284
285 invokeMethod(findMethod(compilationUnitClass, "compile"), compilationUnit);
286
287
288 List<?> classes = (List<?>) invokeMethod(findMethod(compilationUnitClass, "getClasses"), compilationUnit);
289 log.info("Compiled " + classes.size() + " file" + (classes.size() != 1 ? "s" : "") + ".");
290 }
291
292 public void generateGroovyDoc(GroovyDocConfiguration configuration) throws ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException {
293 if (configuration.getSourceDirectories() == null || configuration.getSourceDirectories().length == 0) {
294 log.info("No source directories specified for GroovyDoc generation. Skipping.");
295 return;
296 }
297
298
299
300
301
302
303
304 Class<?> groovyDocToolClass = classWrangler.getClass(configuration.getGroovyDocToolClass() == null ? "org.codehaus.groovy.tools.groovydoc.GroovyDocTool" : configuration.getGroovyDocToolClass());
305 Class<?> outputToolClass = classWrangler.getClass(configuration.getOutputToolClass() == null ? "org.codehaus.groovy.tools.groovydoc.OutputTool" : configuration.getOutputToolClass());
306 Class<?> fileOutputToolClass = classWrangler.getClass(configuration.getFileOutputToolClass() == null ? "org.codehaus.groovy.tools.groovydoc.FileOutputTool" : configuration.getFileOutputToolClass());
307 Class<?> resourceManagerClass = classWrangler.getClass(configuration.getResourceManagerClass() == null ? "org.codehaus.groovy.tools.groovydoc.ResourceManager" : configuration.getResourceManagerClass());
308 Class<?> classpathResourceManagerClass = classWrangler.getClass(configuration.getClasspathResourceManagerClass() == null ? "org.codehaus.groovy.tools.groovydoc.ClasspathResourceManager" : configuration.getClasspathResourceManagerClass());
309
310
311 if (configuration.isAttachGroovyDocAnnotation()) {
312 if (ClassWrangler.groovyAtLeast(classWrangler.getGroovyVersion(), GROOVY_3_0_0_ALPHA4)) {
313 System.setProperty("runtimeGroovydoc", "true");
314 } else {
315 log.warn("Requested to enable attaching GroovyDoc annotation, but your Groovy version (" + classWrangler.getGroovyVersionString() + ") doesn't support it (must be " + GROOVY_3_0_0_ALPHA4 + " or newer). Ignoring enableGroovyDocAnnotation parameter.");
316 }
317 }
318
319 Object fileOutputTool = invokeConstructor(findConstructor(fileOutputToolClass));
320 Object classpathResourceManager = invokeConstructor(findConstructor(classpathResourceManagerClass));
321 FileSetManager fileSetManager = new FileSetManager();
322 List<String> sourceDirectoriesStrings = new ArrayList<>();
323 for (FileSet sourceDirectory : configuration.getSourceDirectories()) {
324 sourceDirectoriesStrings.add(sourceDirectory.getDirectory());
325 }
326 GroovyDocTemplateInfo groovyDocTemplateInfo = new GroovyDocTemplateInfo(classWrangler.getGroovyVersion());
327
328 List<?> groovyDocLinks = setupLinks(configuration);
329
330 if (ClassWrangler.groovyOlderThan(classWrangler.getGroovyVersion(), GROOVY_1_6_0_RC2) && configuration.getDocProperties() != null && !configuration.getDocProperties().isEmpty()) {
331 log.warn("Your Groovy version (" + classWrangler.getGroovyVersionString() + ") doesn't support GroovyDoc documentation properties (docTitle, footer, header, displayAuthor, overviewFile, and scope). You need Groovy 1.6-RC-2 or newer to support this. Ignoring properties.");
332 }
333
334
335 List<String> groovyDocSources = setupGroovyDocSources(configuration.getSourceDirectories(), fileSetManager);
336
337
338 Object groovyDocTool = createGroovyDocTool(groovyDocToolClass, resourceManagerClass, configuration.getDocProperties(), classpathResourceManager, sourceDirectoriesStrings, groovyDocTemplateInfo, groovyDocLinks, configuration);
339
340
341 performGroovyDocGeneration(configuration.getOutputDirectory(), groovyDocToolClass, outputToolClass, fileOutputTool, groovyDocSources, groovyDocTool);
342 }
343
344 @SuppressWarnings({"rawtypes", "unchecked"})
345 protected List<?> setupLinks(GroovyDocConfiguration configuration) throws ClassNotFoundException, InvocationTargetException, IllegalAccessException, InstantiationException {
346 List linksList = new ArrayList();
347 if (configuration.getLinks() != null && !configuration.getLinks().isEmpty()) {
348 Class<?> linkArgumentClass = null;
349 if (configuration.getLinkArgumentClass() == null) {
350 if (ClassWrangler.groovyAtLeast(classWrangler.getGroovyVersion(), GROOVY_1_6_0_RC2)) {
351 linkArgumentClass = classWrangler.getClass("org.codehaus.groovy.tools.groovydoc.LinkArgument");
352 } else if (ClassWrangler.groovyAtLeast(classWrangler.getGroovyVersion(), GROOVY_1_5_2)) {
353 linkArgumentClass = classWrangler.getClass("org.codehaus.groovy.ant.Groovydoc$LinkArgument");
354 }
355 } else {
356 linkArgumentClass = classWrangler.getClass(configuration.getLinkArgumentClass());
357 }
358 if (linkArgumentClass != null) {
359 Method setHref = findMethod(linkArgumentClass, "setHref", String.class);
360 Method setPackages = findMethod(linkArgumentClass, "setPackages", String.class);
361 for (Link link : configuration.getLinks()) {
362 Object linkArgument = invokeConstructor(findConstructor(linkArgumentClass));
363 invokeMethod(setHref, linkArgument, link.getHref());
364 invokeMethod(setPackages, linkArgument, link.getPackages());
365 linksList.add(linkArgument);
366 }
367 } else {
368 log.warn("Requested to use GroovyDoc links, but your Groovy version (" + classWrangler.getGroovyVersionString() + ") doesn't support it (must be 1.5.2 or newer). Ignoring links parameter.");
369 }
370 }
371 return linksList;
372 }
373
374 protected Object createGroovyDocTool(final Class<?> groovyDocToolClass, final Class<?> resourceManagerClass, final Properties docProperties, final Object classpathResourceManager, final List<String> sourceDirectories, final GroovyDocTemplateInfo groovyDocTemplateInfo, final List<?> groovyDocLinks, GroovyDocConfiguration configuration) throws InvocationTargetException, IllegalAccessException, InstantiationException {
375 Object groovyDocTool;
376
377 String[] defaultDocTemplates = configuration.getDefaultDocTemplates();
378 String[] defaultPackageTemplates = configuration.getDefaultPackageTemplates();
379 String[] defaultClassTemplates = configuration.getDefaultClassTemplates();
380
381 if ((ClassWrangler.groovyAtLeast(classWrangler.getGroovyVersion(), GROOVY_4_0_27) && ClassWrangler.groovyOlderThan(classWrangler.getGroovyVersion(), GROOVY_5_0_0_ALPHA1)) || ClassWrangler.groovyAtLeast(classWrangler.getGroovyVersion(), GROOVY_5_0_0_BETA_1)) {
382 groovyDocTool = invokeConstructor(findConstructor(groovyDocToolClass, resourceManagerClass, String[].class, String[].class, String[].class, String[].class, List.class, String.class, Properties.class),
383 classpathResourceManager,
384 sourceDirectories.toArray(new String[0]),
385 defaultDocTemplates == null ? groovyDocTemplateInfo.defaultDocTemplates() : defaultDocTemplates,
386 defaultPackageTemplates == null ? groovyDocTemplateInfo.defaultPackageTemplates() : defaultPackageTemplates,
387 defaultClassTemplates == null ? groovyDocTemplateInfo.defaultClassTemplates() : defaultClassTemplates,
388 groovyDocLinks,
389 configuration.getLanguageLevel(),
390 docProperties
391 );
392 } else if (ClassWrangler.groovyAtLeast(classWrangler.getGroovyVersion(), GROOVY_1_6_0_RC2)) {
393 groovyDocTool = invokeConstructor(findConstructor(groovyDocToolClass, resourceManagerClass, String[].class, String[].class, String[].class, String[].class, List.class, Properties.class),
394 classpathResourceManager,
395 sourceDirectories.toArray(new String[0]),
396 defaultDocTemplates == null ? groovyDocTemplateInfo.defaultDocTemplates() : defaultDocTemplates,
397 defaultPackageTemplates == null ? groovyDocTemplateInfo.defaultPackageTemplates() : defaultPackageTemplates,
398 defaultClassTemplates == null ? groovyDocTemplateInfo.defaultClassTemplates() : defaultClassTemplates,
399 groovyDocLinks,
400 docProperties
401 );
402 } else if (ClassWrangler.groovyAtLeast(classWrangler.getGroovyVersion(), GROOVY_1_5_2)) {
403 groovyDocTool = invokeConstructor(findConstructor(groovyDocToolClass, resourceManagerClass, String.class, String[].class, String[].class, String[].class, List.class),
404 classpathResourceManager,
405 sourceDirectories.get(0),
406 defaultDocTemplates == null ? groovyDocTemplateInfo.defaultDocTemplates() : defaultDocTemplates,
407 defaultPackageTemplates == null ? groovyDocTemplateInfo.defaultPackageTemplates() : defaultPackageTemplates,
408 defaultClassTemplates == null ? groovyDocTemplateInfo.defaultClassTemplates() : defaultClassTemplates,
409 groovyDocLinks
410 );
411 if (sourceDirectories.size() > 1) {
412 log.warn("Your Groovy version (" + classWrangler.getGroovyVersionString() + ") doesn't support more than one GroovyDoc source directory (must be 1.6-RC-2 or newer). Only using first source directory (" + sourceDirectories.get(0) + ").");
413 }
414 } else {
415 groovyDocTool = invokeConstructor(findConstructor(groovyDocToolClass, resourceManagerClass, String.class, String[].class, String[].class, String[].class),
416 classpathResourceManager,
417 sourceDirectories.get(0),
418 defaultDocTemplates == null ? groovyDocTemplateInfo.defaultDocTemplates() : defaultDocTemplates,
419 defaultPackageTemplates == null ? groovyDocTemplateInfo.defaultPackageTemplates() : defaultPackageTemplates,
420 defaultClassTemplates == null ? groovyDocTemplateInfo.defaultClassTemplates() : defaultClassTemplates
421 );
422 if (sourceDirectories.size() > 1) {
423 log.warn("Your Groovy version (" + classWrangler.getGroovyVersionString() + ") doesn't support more than one GroovyDoc source directory (must be 1.6-RC-2 or newer). Only using first source directory (" + sourceDirectories.get(0) + ").");
424 }
425 }
426 return groovyDocTool;
427 }
428
429 protected List<String> setupGroovyDocSources(final FileSet[] sourceDirectories, final FileSetManager fileSetManager) {
430 List<String> javaSources = new ArrayList<>();
431 List<String> groovySources = new ArrayList<>();
432 List<String> possibleGroovyStubs = new ArrayList<>();
433 for (FileSet sourceDirectory : sourceDirectories) {
434 String[] sources = fileSetManager.getIncludedFiles(sourceDirectory);
435 for (String source : sources) {
436 if (source.endsWith(".java") && !javaSources.contains(source)) {
437 javaSources.add(source);
438 } else if (!groovySources.contains(source)) {
439 groovySources.add(source);
440 possibleGroovyStubs.add(source.replaceFirst("\\." + FileUtils.getFileExtension(source), ".java"));
441 }
442 }
443 }
444 javaSources.removeAll(possibleGroovyStubs);
445 List<String> groovyDocSources = new ArrayList<>();
446 groovyDocSources.addAll(javaSources);
447 groovyDocSources.addAll(groovySources);
448
449 return groovyDocSources;
450 }
451
452 protected void performGroovyDocGeneration(final File outputDirectory, final Class<?> groovyDocToolClass, final Class<?> outputToolClass, final Object fileOutputTool, final List<String> groovyDocSources, final Object groovyDocTool) throws InvocationTargetException, IllegalAccessException {
453 log.debug("Adding sources to generate GroovyDoc for:");
454 if (log.isDebugEnabled()) {
455 for (String groovyDocSource : groovyDocSources) {
456 log.debug(" " + groovyDocSource);
457 }
458 }
459 if (ClassWrangler.groovyAtLeast(classWrangler.getGroovyVersion(), GROOVY_1_6_0_RC2)) {
460 invokeMethod(findMethod(groovyDocToolClass, "add", List.class), groovyDocTool, groovyDocSources);
461 } else {
462 Method add = findMethod(groovyDocToolClass, "add", String.class);
463 for (String groovyDocSource : groovyDocSources) {
464 invokeMethod(add, groovyDocTool, groovyDocSource);
465 }
466 }
467 invokeMethod(findMethod(groovyDocToolClass, "renderToOutput", outputToolClass, String.class), groovyDocTool, fileOutputTool, outputDirectory.getAbsolutePath());
468 }
469
470 public void generateStubs(GroovyStubConfiguration configuration) throws ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException {
471
472 if (configuration.getStubSources() == null || configuration.getStubSources().isEmpty()) {
473 log.info("No sources specified for stub generation. Skipping.");
474 return;
475 }
476
477 if (!supportsStubGeneration()) {
478 log.error("Your Groovy version (" + classWrangler.getGroovyVersionString() + ") doesn't support stub generation. The minimum version of Groovy required is 1.8.2. Skipping stub generation.");
479 return;
480 }
481
482 if (!configuration.isSkipBytecodeCheck()) {
483 verifyGroovyVersionSupportsTargetBytecode(configuration.getTargetBytecode());
484 }
485
486
487 Class<?> compilerConfigurationClass = classWrangler.getClass("org.codehaus.groovy.control.CompilerConfiguration");
488 Class<?> javaStubCompilationUnitClass = classWrangler.getClass("org.codehaus.groovy.tools.javac.JavaStubCompilationUnit");
489 Class<?> groovyClassLoaderClass = classWrangler.getClass("groovy.lang.GroovyClassLoader");
490
491
492 Object compilerConfiguration = setupStubCompilerConfiguration(configuration, compilerConfigurationClass);
493 Object groovyClassLoader = invokeConstructor(findConstructor(groovyClassLoaderClass, ClassLoader.class, compilerConfigurationClass), classWrangler.getClassLoader(), compilerConfiguration);
494 Object javaStubCompilationUnit = invokeConstructor(findConstructor(javaStubCompilationUnitClass, compilerConfigurationClass, groovyClassLoaderClass, File.class), compilerConfiguration, groovyClassLoader, configuration.getOutputDirectory());
495
496
497 addGroovySources(configuration.getStubSources(), compilerConfigurationClass, javaStubCompilationUnitClass, compilerConfiguration, javaStubCompilationUnit);
498
499
500 invokeMethod(findMethod(javaStubCompilationUnitClass, "compile"), javaStubCompilationUnit);
501 }
502
503 protected Object setupStubCompilerConfiguration(final GroovyStubConfiguration configuration, final Class<?> compilerConfigurationClass) throws InvocationTargetException, IllegalAccessException, InstantiationException {
504 Object compilerConfiguration = invokeConstructor(findConstructor(compilerConfigurationClass));
505 invokeMethod(findMethod(compilerConfigurationClass, "setDebug", boolean.class), compilerConfiguration, configuration.isDebug());
506 invokeMethod(findMethod(compilerConfigurationClass, "setVerbose", boolean.class), compilerConfiguration, configuration.isVerbose());
507 invokeMethod(findMethod(compilerConfigurationClass, "setWarningLevel", int.class), compilerConfiguration, configuration.getWarningLevel());
508 invokeMethod(findMethod(compilerConfigurationClass, "setTolerance", int.class), compilerConfiguration, configuration.getTolerance());
509 invokeMethod(findMethod(compilerConfigurationClass, "setTargetBytecode", String.class), compilerConfiguration, translateJavacTargetToTargetBytecode(configuration.getTargetBytecode()));
510 if (configuration.getSourceEncoding() != null) {
511 invokeMethod(findMethod(compilerConfigurationClass, "setSourceEncoding", String.class), compilerConfiguration, configuration.getSourceEncoding());
512 }
513 Map<String, Object> options = new HashMap<>();
514 options.put("stubDir", configuration.getOutputDirectory());
515 options.put("keepStubs", Boolean.TRUE);
516 invokeMethod(findMethod(compilerConfigurationClass, "setJointCompilationOptions", Map.class), compilerConfiguration, options);
517
518 return compilerConfiguration;
519 }
520
521 protected void addGroovySources(final Set<File> stubSources, final Class<?> compilerConfigurationClass, final Class<?> javaStubCompilationUnitClass, final Object compilerConfiguration, final Object javaStubCompilationUnit) throws InvocationTargetException, IllegalAccessException {
522
523
524
525
526
527
528 Set<String> scriptExtensions = new java.util.HashSet<>();
529 for (File stubSource : stubSources) {
530 scriptExtensions.add(FileUtils.getFileExtension(stubSource));
531 }
532 log.debug("Detected Groovy file extensions: " + scriptExtensions + ".");
533 if (supportsSettingExtensions()) {
534 invokeMethod(findMethod(compilerConfigurationClass, "setScriptExtensions", Set.class), compilerConfiguration, scriptExtensions);
535 }
536 log.debug("Adding Groovy to generate stubs for:");
537 Method addSource = findMethod(javaStubCompilationUnitClass, "addSource", File.class);
538 for (File stubSource : stubSources) {
539 log.debug(" " + stubSource);
540 if (supportsSettingExtensions()) {
541 invokeMethod(addSource, javaStubCompilationUnit, stubSource);
542 } else {
543
544
545
546 org.codehaus.gmavenplus.groovyworkarounds.DotGroovyFile dotGroovyFile = new org.codehaus.gmavenplus.groovyworkarounds.DotGroovyFile(stubSource).setScriptExtensions(scriptExtensions);
547 invokeMethod(addSource, javaStubCompilationUnit, dotGroovyFile);
548 }
549 }
550 }
551
552 protected boolean supportsStubGeneration() {
553 return ClassWrangler.groovyAtLeast(classWrangler.getGroovyVersion(), GROOVY_1_8_2);
554 }
555
556 protected boolean supportsSettingExtensions() {
557 return ClassWrangler.groovyAtLeast(classWrangler.getGroovyVersion(), GROOVY_1_8_3) && (ClassWrangler.groovyOlderThan(classWrangler.getGroovyVersion(), GROOVY_1_9_0_BETA1) || ClassWrangler.groovyNewerThan(classWrangler.getGroovyVersion(), GROOVY_1_9_0_BETA3));
558 }
559
560 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 {
561 Object compilationUnit;
562 if (ClassWrangler.groovyAtLeast(classWrangler.getGroovyVersion(), GROOVY_1_6_0)) {
563 compilationUnit = invokeConstructor(findConstructor(compilationUnitClass, compilerConfigurationClass, CodeSource.class, groovyClassLoaderClass, groovyClassLoaderClass), compilerConfiguration, null, groovyClassLoader, transformLoader);
564 } else {
565 compilationUnit = invokeConstructor(findConstructor(compilationUnitClass, compilerConfigurationClass, CodeSource.class, groovyClassLoaderClass), compilerConfiguration, null, groovyClassLoader);
566 }
567 log.debug("Adding Groovy to compile:");
568 Method addSourceMethod = findMethod(compilationUnitClass, "addSource", File.class);
569 for (File source : sources) {
570 log.debug(" " + source);
571 invokeMethod(addSourceMethod, compilationUnit, source);
572 }
573
574 return compilationUnit;
575 }
576
577 @SuppressWarnings({"rawtypes", "unchecked"})
578 protected Object setupCompilerConfiguration(final GroovyCompileConfiguration configuration, final Class<?> compilerConfigurationClass) throws InvocationTargetException, IllegalAccessException, InstantiationException, ClassNotFoundException {
579 Object compilerConfiguration = invokeConstructor(findConstructor(compilerConfigurationClass));
580 if (configuration.getConfigScript() != null) {
581 if (!configuration.getConfigScript().exists()) {
582 log.warn("Configuration script file (" + configuration.getConfigScript().getAbsolutePath() + ") doesn't exist. Ignoring configScript parameter.");
583 } else if (ClassWrangler.groovyOlderThan(classWrangler.getGroovyVersion(), GROOVY_2_1_0_BETA1)) {
584 log.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.");
585 } else {
586 Class<?> bindingClass = classWrangler.getClass("groovy.lang.Binding");
587 Class<?> importCustomizerClass = classWrangler.getClass("org.codehaus.groovy.control.customizers.ImportCustomizer");
588 Class<?> groovyShellClass = classWrangler.getClass("groovy.lang.GroovyShell");
589
590 Object binding = invokeConstructor(findConstructor(bindingClass));
591 invokeMethod(findMethod(bindingClass, "setVariable", String.class, Object.class), binding, "configuration", compilerConfiguration);
592 Object shellCompilerConfiguration = invokeConstructor(findConstructor(compilerConfigurationClass));
593 Object importCustomizer = invokeConstructor(findConstructor(importCustomizerClass));
594 invokeMethod(findMethod(importCustomizerClass, "addStaticStar", String.class), importCustomizer, "org.codehaus.groovy.control.customizers.builder.CompilerCustomizationBuilder");
595 List compilationCustomizers = (List) invokeMethod(findMethod(compilerConfigurationClass, "getCompilationCustomizers"), shellCompilerConfiguration);
596 compilationCustomizers.add(importCustomizer);
597 Object shell = invokeConstructor(findConstructor(groovyShellClass, ClassLoader.class, bindingClass, compilerConfigurationClass), classWrangler.getClassLoader(), binding, shellCompilerConfiguration);
598 log.debug("Using configuration script " + configuration.getConfigScript() + " for compilation.");
599 invokeMethod(findMethod(groovyShellClass, "evaluate", File.class), shell, configuration.getConfigScript());
600 }
601 }
602 invokeMethod(findMethod(compilerConfigurationClass, "setDebug", boolean.class), compilerConfiguration, configuration.isDebug());
603 invokeMethod(findMethod(compilerConfigurationClass, "setVerbose", boolean.class), compilerConfiguration, configuration.isVerbose());
604 invokeMethod(findMethod(compilerConfigurationClass, "setWarningLevel", int.class), compilerConfiguration, configuration.getWarningLevel());
605 invokeMethod(findMethod(compilerConfigurationClass, "setTolerance", int.class), compilerConfiguration, configuration.getTolerance());
606 invokeMethod(findMethod(compilerConfigurationClass, "setTargetBytecode", String.class), compilerConfiguration, translateJavacTargetToTargetBytecode(configuration.getTargetBytecode()));
607 if (configuration.isPreviewFeatures()) {
608 if (isJavaSupportPreviewFeatures()) {
609 if (ClassWrangler.groovyOlderThan(classWrangler.getGroovyVersion(), GROOVY_2_5_7) || (ClassWrangler.groovyAtLeast(classWrangler.getGroovyVersion(), GROOVY_2_6_0_ALPHA1) && ClassWrangler.groovyOlderThan(classWrangler.getGroovyVersion(), GROOVY_3_0_0_BETA1))) {
610 log.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.");
611 } else {
612 invokeMethod(findMethod(compilerConfigurationClass, "setPreviewFeatures", boolean.class), compilerConfiguration, configuration.isPreviewFeatures());
613 }
614 } else {
615 log.warn("Requested to use to use preview features, but your Java version (" + getJavaVersionString() + ") doesn't support it. Ignoring previewFeatures parameter.");
616 }
617 }
618 if (configuration.getSourceEncoding() != null) {
619 invokeMethod(findMethod(compilerConfigurationClass, "setSourceEncoding", String.class), compilerConfiguration, configuration.getSourceEncoding());
620 }
621 invokeMethod(findMethod(compilerConfigurationClass, "setTargetDirectory", String.class), compilerConfiguration, configuration.getCompileOutputDirectory().getAbsolutePath());
622 if (configuration.isInvokeDynamic() || ClassWrangler.groovyAtLeast(classWrangler.getGroovyVersion(), GROOVY_4_0_0_ALPHA1)) {
623 if (ClassWrangler.groovyAtLeast(classWrangler.getGroovyVersion(), GROOVY_2_0_0_BETA3)) {
624 if (classWrangler.isGroovyIndy()) {
625 if (isJavaSupportIndy()) {
626 Map<String, Boolean> optimizationOptions = (Map<String, Boolean>) invokeMethod(findMethod(compilerConfigurationClass, "getOptimizationOptions"), compilerConfiguration);
627 optimizationOptions.put("indy", true);
628 optimizationOptions.put("int", false);
629 log.info("invokedynamic enabled.");
630 } else {
631 log.warn("Requested to use to use invokedynamic, but your Java version (" + getJavaVersionString() + ") doesn't support it. Ignoring invokeDynamic parameter.");
632 }
633 } else {
634 log.warn("Requested to use invokedynamic, but your Groovy version doesn't support it (must use have indy classifier). Ignoring invokeDynamic parameter.");
635 }
636 } else {
637 log.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.");
638 }
639 }
640 if (configuration.isParameters()) {
641 if (ClassWrangler.groovyAtLeast(classWrangler.getGroovyVersion(), GROOVY_2_5_0_ALPHA1)) {
642 if (isJavaSupportParameters()) {
643 invokeMethod(findMethod(compilerConfigurationClass, "setParameters", boolean.class), compilerConfiguration, configuration.isParameters());
644 } else {
645 log.warn("Requested to use to use parameters, but your Java version (" + getJavaVersionString() + ") doesn't support it. Ignoring parameters parameter.");
646 }
647 } else {
648 log.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.");
649 }
650 }
651 if (ClassWrangler.groovyAtLeast(classWrangler.getGroovyVersion(), GROOVY_3_0_5)) {
652 if ((configuration.getParallelParsing() == null && ClassWrangler.groovyAtLeast(classWrangler.getGroovyVersion(), GROOVY_4_0_0_ALPHA1)) || (configuration.getParallelParsing() != null && configuration.getParallelParsing())) {
653 Map<String, Boolean> optimizationOptions = (Map<String, Boolean>) invokeMethod(findMethod(compilerConfigurationClass, "getOptimizationOptions"), compilerConfiguration);
654 optimizationOptions.put("parallelParse", true);
655 log.info("Parallel parsing enabled.");
656 } else {
657 log.info("Parallel parsing disabled.");
658 }
659 }
660
661 return compilerConfiguration;
662 }
663
664 protected void verifyGroovyVersionSupportsTargetBytecode(String targetBytecode) {
665 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)) {
666 if (ClassWrangler.groovyNewerThan(classWrangler.getGroovyVersion(), GROOVY_5_0_0_ALPHA1)) {
667 throw new IllegalArgumentException("Target bytecode " + targetBytecode + " isn't accepted by Groovy " + GROOVY_5_0_0_ALPHA1 + " or newer.");
668 }
669 }
670
671 if ("25".equals(targetBytecode)) {
672 if (ClassWrangler.groovyOlderThan(classWrangler.getGroovyVersion(), GROOVY_4_0_27)) {
673 throw new IllegalArgumentException("Target bytecode " + targetBytecode + " requires Groovy " + GROOVY_4_0_27 + " or newer.");
674 }
675 if (ClassWrangler.groovyNewerThan(classWrangler.getGroovyVersion(), GROOVY_5_0_0_ALPHA1) && ClassWrangler.groovyOlderThan(classWrangler.getGroovyVersion(), GROOVY_5_0_0_ALPHA13)) {
676 throw new IllegalArgumentException("Target bytecode " + targetBytecode + " requires Groovy " + GROOVY_5_0_0_ALPHA13 + " or newer.");
677 }
678 } else if ("24".equals(targetBytecode)) {
679 if (ClassWrangler.groovyOlderThan(classWrangler.getGroovyVersion(), GROOVY_4_0_24)) {
680 throw new IllegalArgumentException("Target bytecode " + targetBytecode + " requires Groovy " + GROOVY_4_0_24 + " or newer.");
681 }
682 if (ClassWrangler.groovyNewerThan(classWrangler.getGroovyVersion(), GROOVY_5_0_0_ALPHA1) && ClassWrangler.groovyOlderThan(classWrangler.getGroovyVersion(), GROOVY_5_0_0_ALPHA11)) {
683 throw new IllegalArgumentException("Target bytecode " + targetBytecode + " requires Groovy " + GROOVY_5_0_0_ALPHA11 + " or newer.");
684 }
685 } else if ("23".equals(targetBytecode)) {
686 if (ClassWrangler.groovyOlderThan(classWrangler.getGroovyVersion(), GROOVY_4_0_21)) {
687 throw new IllegalArgumentException("Target bytecode " + targetBytecode + " requires Groovy " + GROOVY_4_0_21 + " or newer.");
688 }
689 if (ClassWrangler.groovyNewerThan(classWrangler.getGroovyVersion(), GROOVY_5_0_0_ALPHA1) && ClassWrangler.groovyOlderThan(classWrangler.getGroovyVersion(), GROOVY_5_0_0_ALPHA8)) {
690 throw new IllegalArgumentException("Target bytecode " + targetBytecode + " requires Groovy " + GROOVY_5_0_0_ALPHA8 + " or newer.");
691 }
692 } else if ("22".equals(targetBytecode)) {
693 if (ClassWrangler.groovyOlderThan(classWrangler.getGroovyVersion(), GROOVY_4_0_16)) {
694 throw new IllegalArgumentException("Target bytecode " + targetBytecode + " requires Groovy " + GROOVY_4_0_16 + " or newer.");
695 }
696 if (ClassWrangler.groovyNewerThan(classWrangler.getGroovyVersion(), GROOVY_5_0_0_ALPHA1) && ClassWrangler.groovyOlderThan(classWrangler.getGroovyVersion(), GROOVY_5_0_0_ALPHA3)) {
697 throw new IllegalArgumentException("Target bytecode " + targetBytecode + " requires Groovy " + GROOVY_5_0_0_ALPHA3 + " or newer.");
698 }
699 } else if ("21".equals(targetBytecode)) {
700 if (ClassWrangler.groovyOlderThan(classWrangler.getGroovyVersion(), GROOVY_4_0_11)) {
701 throw new IllegalArgumentException("Target bytecode " + targetBytecode + " requires Groovy " + GROOVY_4_0_11 + " or newer.");
702 }
703 } else if ("20".equals(targetBytecode)) {
704 if (ClassWrangler.groovyOlderThan(classWrangler.getGroovyVersion(), GROOVY_4_0_6)) {
705 throw new IllegalArgumentException("Target bytecode " + targetBytecode + " requires Groovy " + GROOVY_4_0_6 + " or newer.");
706 }
707 } else if ("19".equals(targetBytecode)) {
708 if (ClassWrangler.groovyOlderThan(classWrangler.getGroovyVersion(), GROOVY_4_0_2)) {
709 throw new IllegalArgumentException("Target bytecode " + targetBytecode + " requires Groovy " + GROOVY_4_0_2 + " or newer.");
710 }
711 } else if ("18".equals(targetBytecode)) {
712 if (ClassWrangler.groovyOlderThan(classWrangler.getGroovyVersion(), GROOVY_4_0_0_BETA1)) {
713 throw new IllegalArgumentException("Target bytecode " + targetBytecode + " requires Groovy " + GROOVY_4_0_0_BETA1 + " or newer.");
714 }
715 } else if ("17".equals(targetBytecode)) {
716 if (ClassWrangler.groovyOlderThan(classWrangler.getGroovyVersion(), GROOVY_3_0_8) || (ClassWrangler.groovyAtLeast(classWrangler.getGroovyVersion(), GROOVY_4_0_0_ALPHA1) && ClassWrangler.groovyOlderThan(classWrangler.getGroovyVersion(), GROOVY_4_0_0_ALPHA3))) {
717 throw new IllegalArgumentException("Target bytecode " + targetBytecode + " requires Groovy " + GROOVY_3_0_8 + "/" + GROOVY_4_0_0_ALPHA3 + " or newer.");
718 }
719 } else if ("16".equals(targetBytecode)) {
720 if (ClassWrangler.groovyOlderThan(classWrangler.getGroovyVersion(), GROOVY_3_0_6)) {
721 throw new IllegalArgumentException("Target bytecode " + targetBytecode + " requires Groovy " + GROOVY_3_0_6 + " or newer.");
722 }
723 } else if ("15".equals(targetBytecode)) {
724 if (ClassWrangler.groovyOlderThan(classWrangler.getGroovyVersion(), GROOVY_3_0_3)) {
725 throw new IllegalArgumentException("Target bytecode " + targetBytecode + " requires Groovy " + GROOVY_3_0_3 + " or newer.");
726 }
727 } else if ("14".equals(targetBytecode)) {
728 if (ClassWrangler.groovyOlderThan(classWrangler.getGroovyVersion(), GROOVY_3_0_0_BETA2)) {
729 throw new IllegalArgumentException("Target bytecode " + targetBytecode + " requires Groovy " + GROOVY_3_0_0_BETA2 + " or newer.");
730 }
731 } else if ("13".equals(targetBytecode)) {
732 if (ClassWrangler.groovyOlderThan(classWrangler.getGroovyVersion(), GROOVY_2_5_7) || (ClassWrangler.groovyAtLeast(classWrangler.getGroovyVersion(), GROOVY_2_6_0_ALPHA1) && ClassWrangler.groovyOlderThan(classWrangler.getGroovyVersion(), GROOVY_3_0_0_BETA1))) {
733 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.");
734 }
735 } else if ("12".equals(targetBytecode) || "11".equals(targetBytecode) || "10".equals(targetBytecode)) {
736 if (ClassWrangler.groovyOlderThan(classWrangler.getGroovyVersion(), GROOVY_2_5_3) || (ClassWrangler.groovyAtLeast(classWrangler.getGroovyVersion(), GROOVY_2_6_0_ALPHA1) && ClassWrangler.groovyOlderThan(classWrangler.getGroovyVersion(), GROOVY_3_0_0_ALPHA4))) {
737 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.");
738 }
739 } else if ("9".equals(targetBytecode) || "1.9".equals(targetBytecode)) {
740 if (!classWrangler.isGroovyIndy() && (ClassWrangler.groovyOlderThan(classWrangler.getGroovyVersion(), GROOVY_2_5_3)
741 || (ClassWrangler.groovyAtLeast(classWrangler.getGroovyVersion(), GROOVY_2_6_0_ALPHA1) && ClassWrangler.groovyOlderThan(classWrangler.getGroovyVersion(), GROOVY_2_6_0_ALPHA4))
742 || (ClassWrangler.groovyAtLeast(classWrangler.getGroovyVersion(), GROOVY_3_0_0_ALPHA1) && ClassWrangler.groovyOlderThan(classWrangler.getGroovyVersion(), GROOVY_3_0_0_ALPHA2)))) {
743 throw new IllegalArgumentException("Target bytecode " + targetBytecode + " requires Groovy " + GROOVY_2_5_3 + "/" + GROOVY_2_6_0_ALPHA4 + "/" + GROOVY_3_0_0_ALPHA2 + " or newer.");
744 } else if (classWrangler.isGroovyIndy() && (ClassWrangler.groovyOlderThan(classWrangler.getGroovyVersion(), GROOVY_2_5_3) || (ClassWrangler.groovyAtLeast(classWrangler.getGroovyVersion(), GROOVY_2_6_0_ALPHA1) && ClassWrangler.groovyOlderThan(classWrangler.getGroovyVersion(), GROOVY_3_0_0_ALPHA4)))) {
745 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.");
746 }
747 } else if ("8".equals(targetBytecode) || "1.8".equals(targetBytecode)) {
748 if (ClassWrangler.groovyOlderThan(classWrangler.getGroovyVersion(), GROOVY_2_3_3)) {
749 throw new IllegalArgumentException("Target bytecode " + targetBytecode + " requires Groovy " + GROOVY_2_3_3 + " or newer.");
750 }
751 } else if ("7".equals(targetBytecode) || "1.7".equals(targetBytecode) || "6".equals(targetBytecode) || "1.6".equals(targetBytecode)) {
752 if (ClassWrangler.groovyOlderThan(classWrangler.getGroovyVersion(), GROOVY_2_1_3)) {
753 throw new IllegalArgumentException("Target bytecode " + targetBytecode + " requires Groovy " + GROOVY_2_1_3 + " or newer.");
754 }
755 } else if (!"5".equals(targetBytecode) && !"1.5".equals(targetBytecode) && !"4".equals(targetBytecode) && !"1.4".equals(targetBytecode)) {
756 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.");
757 }
758 }
759
760 public static String translateJavacTargetToTargetBytecode(String targetBytecode) {
761 Map<String, String> javacTargetToTargetBytecode = new HashMap<>();
762 javacTargetToTargetBytecode.put("5", "1.5");
763 javacTargetToTargetBytecode.put("6", "1.6");
764 javacTargetToTargetBytecode.put("7", "1.7");
765 javacTargetToTargetBytecode.put("8", "1.8");
766 javacTargetToTargetBytecode.put("1.9", "9");
767 return javacTargetToTargetBytecode.getOrDefault(targetBytecode, targetBytecode);
768 }
769
770 protected boolean isJavaSupportIndy() {
771 return getJavaVersion().compareTo(JAVA_1_7, false) >= 0;
772 }
773
774 protected boolean isJavaSupportPreviewFeatures() {
775 return getJavaVersion().compareTo(JAVA_12, false) >= 0;
776 }
777
778 protected boolean isJavaSupportParameters() {
779 return getJavaVersion().compareTo(JAVA_1_8, false) >= 0;
780 }
781
782 protected Version getJavaVersion() {
783 return Version.parseFromString(getJavaVersionString());
784 }
785
786 protected String getJavaVersionString() {
787 return System.getProperty("java.version");
788 }
789
790 }