View Javadoc
1   /*
2    * Copyright (C) 2011 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
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   * The base generate stubs mojo, which all generate stubs mojos extend.
43   *
44   * @author Keegan Witt
45   * @since 1.0-beta-1
46   */
47  public abstract class AbstractGenerateStubsMojo extends AbstractGroovyStubSourcesMojo {
48  
49      /**
50       * Groovy 5.0.0-alpha-13 version.
51       */
52      protected static final Version GROOVY_5_0_0_ALPHA13 = new Version(5, 0, 0, "alpha-13");
53  
54      /**
55       * Groovy 5.0.0-alpha-11 version.
56       */
57      protected static final Version GROOVY_5_0_0_ALPHA11 = new Version(5, 0, 0, "alpha-11");
58  
59      /**
60       * Groovy 5.0.0-alpha-8 version.
61       */
62      protected static final Version GROOVY_5_0_0_ALPHA8 = new Version(5, 0, 0, "alpha-8");
63  
64      /**
65       * Groovy 5.0.0-alpha-3 version.
66       */
67      protected static final Version GROOVY_5_0_0_ALPHA3 = new Version(5, 0, 0, "alpha-3");
68  
69      /**
70       * Groovy 5.0.0-alpha-1 version.
71       */
72      protected static final Version GROOVY_5_0_0_ALPHA1 = new Version(5, 0, 0, "alpha-1");
73  
74      /**
75       * Groovy 4.0.27 version.
76       */
77      protected static final Version GROOVY_4_0_27 = new Version(4, 0, 27);
78  
79      /**
80       * Groovy 4.0.24 version.
81       */
82      protected static final Version GROOVY_4_0_24 = new Version(4, 0, 24);
83  
84      /**
85       * Groovy 4.0.21 version.
86       */
87      protected static final Version GROOVY_4_0_21 = new Version(4, 0, 21);
88  
89      /**
90       * Groovy 4.0.11 version.
91       */
92      protected static final Version GROOVY_4_0_16 = new Version(4, 0, 16);
93  
94      /**
95       * Groovy 4.0.11 version.
96       */
97      protected static final Version GROOVY_4_0_11 = new Version(4, 0, 11);
98  
99      /**
100      * Groovy 4.0.6 version.
101      */
102     protected static final Version GROOVY_4_0_6 = new Version(4, 0, 6);
103 
104     /**
105      * Groovy 4.0.2 version.
106      */
107     protected static final Version GROOVY_4_0_2 = new Version(4, 0, 2);
108 
109     /**
110      * Groovy 4.0.0 beta-1 version.
111      */
112     protected static final Version GROOVY_4_0_0_BETA1 = new Version(4, 0, 0, "beta-1");
113 
114     /**
115      * Groovy 4.0.0 alpha-3 version.
116      */
117     protected static final Version GROOVY_4_0_0_ALPHA3 = new Version(4, 0, 0, "alpha-3");
118 
119     /**
120      * Groovy 4.0.0 alpha-1 version.
121      */
122     protected static final Version GROOVY_4_0_0_ALPHA1 = new Version(4, 0, 0, "alpha-1");
123 
124     /**
125      * Groovy 3.0.8 version.
126      */
127     protected static final Version GROOVY_3_0_8 = new Version(3, 0, 8);
128 
129     /**
130      * Groovy 3.0.6 version.
131      */
132     protected static final Version GROOVY_3_0_6 = new Version(3, 0, 6);
133 
134     /**
135      * Groovy 3.0.3 version.
136      */
137     protected static final Version GROOVY_3_0_3 = new Version(3, 0, 3);
138 
139     /**
140      * Groovy 3.0.0 beta-2 version.
141      */
142     protected static final Version GROOVY_3_0_0_BETA2 = new Version(3, 0, 0, "beta-2");
143 
144     /**
145      * Groovy 3.0.0 beta-1 version.
146      */
147     protected static final Version GROOVY_3_0_0_BETA1 = new Version(3, 0, 0, "beta-1");
148 
149     /**
150      * Groovy 3.0.0 alpha-4 version.
151      */
152     protected static final Version GROOVY_3_0_0_ALPHA4 = new Version(3, 0, 0, "alpha-4");
153 
154     /**
155      * Groovy 3.0.0 alpha-2 version.
156      */
157     protected static final Version GROOVY_3_0_0_ALPHA2 = new Version(3, 0, 0, "alpha-2");
158 
159     /**
160      * Groovy 3.0.0 alpha-1 version.
161      */
162     protected static final Version GROOVY_3_0_0_ALPHA1 = new Version(3, 0, 0, "alpha-1");
163 
164     /**
165      * Groovy 2.6.0 alpha-4 version.
166      */
167     protected static final Version GROOVY_2_6_0_ALPHA4 = new Version(2, 6, 0, "alpha-4");
168 
169     /**
170      * Groovy 2.6.0 alpha-1 version.
171      */
172     protected static final Version GROOVY_2_6_0_ALPHA1 = new Version(2, 6, 0, "alpha-1");
173 
174     /**
175      * Groovy 2.5.7 version.
176      */
177     protected static final Version GROOVY_2_5_7 = new Version(2, 5, 7);
178 
179     /**
180      * Groovy 2.5.3 version.
181      */
182     protected static final Version GROOVY_2_5_3 = new Version(2, 5, 3);
183 
184     /**
185      * Groovy 2.3.3 version.
186      */
187     protected static final Version GROOVY_2_3_3 = new Version(2, 3, 3);
188 
189     /**
190      * Groovy 2.1.3 version.
191      */
192     protected static final Version GROOVY_2_1_3 = new Version(2, 1, 3);
193 
194     /**
195      * Groovy 2.9.0 beta-1 version.
196      */
197     protected static final Version GROOVY_1_9_0_BETA1 = new Version(1, 9, 0, "beta-1");
198 
199     /**
200      * Groovy 1.9.0 beta-3 version.
201      */
202     protected static final Version GROOVY_1_9_0_BETA3 = new Version(1, 9, 0, "beta-3");
203 
204     /**
205      * Groovy 1.8.2 version.
206      */
207     protected static final Version GROOVY_1_8_2 = new Version(1, 8, 2);
208 
209     /**
210      * Groovy 1.8.3 version.
211      */
212     protected static final Version GROOVY_1_8_3 = new Version(1, 8, 3);
213 
214     /**
215      * The encoding of source files.
216      */
217     @Parameter(defaultValue = "${project.build.sourceEncoding}")
218     protected String sourceEncoding;
219 
220     /**
221      * The Groovy compiler bytecode compatibility. One of
222      * <ul>
223      *   <li>1.4 (or 4)</li>
224      *   <li>1.5 (or 5)</li>
225      *   <li>1.6 (or 6)</li>
226      *   <li>1.7 (or 7)</li>
227      *   <li>1.8 (or 8)</li>
228      *   <li>9 (or 1.9)</li>
229      *   <li>10</li>
230      *   <li>11</li>
231      *   <li>12</li>
232      *   <li>13</li>
233      *   <li>14</li>
234      *   <li>15</li>
235      *   <li>16</li>
236      *   <li>17</li>
237      *   <li>18</li>
238      *   <li>19</li>
239      *   <li>20</li>
240      *   <li>21</li>
241      *   <li>22</li>
242      *   <li>23</li>
243      *   <li>24</li>
244      *   <li>25</li>
245      * </ul>
246      * Using 1.6 (or 6) or 1.7 (or 7) requires Groovy &gt;= 2.1.3.
247      * Using 1.8 (or 8) requires Groovy &gt;= 2.3.3.
248      * Using 9 (or 1.9) requires Groovy &gt;= 2.5.3, or Groovy &gt;= 2.6.0 alpha 4, or Groovy &gt;= 3.0.0 alpha 2.
249      * Using 9 (or 1.9) with invokedynamic requires Groovy &gt;= 2.5.3, or Groovy &gt;= 3.0.0 alpha 2, but not any 2.6 versions.
250      * Using 10, 11, or 12 requires Groovy &gt;= 2.5.3, or Groovy &gt;= 3.0.0 alpha 4, but not any 2.6 versions.
251      * Using 13 requires Groovy &gt;= 2.5.7, or Groovy &gt;= 3.0.0-beta-1, but not any 2.6 versions.
252      * Using 14 requires Groovy &gt;= 3.0.0 beta-2.
253      * Using 15 requires Groovy &gt;= 3.0.3.
254      * Using 16 requires Groovy &gt;= 3.0.6.
255      * Using 17 requires Groovy &gt;= 3.0.8 or Groovy &gt; 4.0.0-alpha-3.
256      * Using 18 requires Groovy &gt; 4.0.0-beta-1.
257      * Using 19 requires Groovy &gt; 4.0.2.
258      * Using 20 requires Groovy &gt; 4.0.6.
259      * Using 21 requires Groovy &gt; 4.0.11.
260      * Using 22 requires Groovy &gt; 4.0.16 or Groovy &gt; 5.0.0-alpha-3.
261      * Using 23 requires Groovy &gt; 4.0.21 or Groovy &gt; 5.0.0-alpha-8.
262      * Using 24 requires Groovy &gt; 4.0.24 or Groovy &gt; 5.0.0-alpha-11.
263      * Using 25 requires Groovy &gt; 4.0.27 or Groovy &gt; 5.0.0-alpha-13.
264      *
265      * @since 1.0-beta-3
266      */
267     @Parameter(property = "maven.compiler.target", defaultValue = "1.8")
268     protected String targetBytecode;
269 
270     /**
271      * Whether to check that the version of Groovy used is able to use the requested <code>targetBytecode</code>.
272      *
273      * @since 1.9.0
274      */
275     @Parameter(property = "skipBytecodeCheck", defaultValue = "false")
276     protected boolean skipBytecodeCheck;
277 
278     /**
279      * Whether Groovy compiler should be set to debug.
280      */
281     @Parameter(defaultValue = "false")
282     protected boolean debug;
283 
284     /**
285      * Whether Groovy compiler should be set to verbose.
286      */
287     @Parameter(defaultValue = "false")
288     protected boolean verbose;
289 
290     /**
291      * Groovy compiler warning level. Should be one of:
292      * <dl>
293      *   <dt>0</dt>
294      *     <dd>None</dd>
295      *   <dt>1</dt>
296      *     <dd>Likely Errors</dd>
297      *   <dt>2</dt>
298      *     <dd>Possible Errors</dd>
299      *   <dt>3</dt>
300      *     <dd>Paranoia</dd>
301      * </dl>
302      */
303     @Parameter(defaultValue = "1")
304     protected int warningLevel;
305 
306     /**
307      * Groovy compiler error tolerance (the number of non-fatal errors (per unit) that should be tolerated before compilation is aborted).
308      */
309     @Parameter(defaultValue = "0")
310     protected int tolerance;
311 
312     /**
313      * What classpath to include. One of
314      * <ul>
315      *   <li>PROJECT_ONLY</li>
316      *   <li>PROJECT_AND_PLUGIN</li>
317      *   <li>PLUGIN_ONLY</li>
318      * </ul>
319      * Uses the same scope as the required dependency resolution of this mojo. Use only if you know what you're doing.
320      *
321      * @since 1.8.0
322      */
323     @Parameter(defaultValue = "PROJECT_ONLY")
324     protected IncludeClasspath includeClasspath;
325 
326     /**
327      * Performs the stub generation on the specified source files.
328      *
329      * @param stubSources     the sources to perform stub generation on
330      * @param classpath       The classpath to use for compilation
331      * @param outputDirectory the directory to write the stub files to
332      * @throws ClassNotFoundException    when a class needed for stub generation cannot be found
333      * @throws InstantiationException    when a class needed for stub generation cannot be instantiated
334      * @throws IllegalAccessException    when a method needed for stub generation cannot be accessed
335      * @throws InvocationTargetException when a reflection invocation needed for stub generation cannot be completed
336      * @throws MalformedURLException     when a classpath element provides a malformed URL
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         // get classes we need with reflection
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         // setup stub generation options
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         // add Groovy sources
369         addGroovySources(stubSources, compilerConfigurationClass, javaStubCompilationUnitClass, compilerConfiguration, javaStubCompilationUnit);
370 
371         // generate the stubs
372         invokeMethod(findMethod(javaStubCompilationUnitClass, "compile"), javaStubCompilationUnit);
373     }
374 
375     /**
376      * Sets up the CompilerConfiguration to use for stub generation.
377      *
378      * @param outputDirectory            the directory to write the stub files to
379      * @param compilerConfigurationClass the CompilerConfiguration class
380      * @return the CompilerConfiguration to use for stub generation
381      * @throws InstantiationException    when a class needed for stub generation cannot be instantiated
382      * @throws IllegalAccessException    when a method needed for stub generation cannot be accessed
383      * @throws InvocationTargetException when a reflection invocation needed for stub generation cannot be completed
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      * Adds the Groovy sources to the CompilationUnit.
405      *
406      * @param stubSources                  the sources to perform stub generation on
407      * @param compilerConfigurationClass   the CompilerConfiguration class
408      * @param javaStubCompilationUnitClass the JavaStubCompilationUnit class
409      * @param compilerConfiguration        the CompilerConfiguration to use for stub generation
410      * @param javaStubCompilationUnit      the JavaStubCompilationUnit to use for stub generation
411      * @throws IllegalAccessException    when a method needed for stub generation cannot be accessed
412      * @throws InvocationTargetException when a reflection invocation needed for stub generation cannot be completed
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      * Determines whether the version of Groovy supports stub generation.
438      *
439      * @return <code>true</code> if the version of Groovy supports stub generation, <code>false</code> otherwise
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      * Logs the stubs that have been generated.
447      *
448      * @param outputDirectory the output directory for the stubs
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      * This is a fix for <a href="http://jira.codehaus.org/browse/MGROOVY-187">...</a>
457      * It modifies the dates of the created stubs to 1/1/1970, ensuring that the Java compiler will not overwrite perfectly
458      * good compiled Groovy just because it has a newer source stub. Basically, this prevents the stubs from causing a
459      * side effect with the Java compiler, but still allows stubs to work with JavaDoc.
460      *
461      * @param stubs the files on which to reset the modified date
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      * Throws an exception if targetBytecode is not supported with this version of Groovy. That is, when Groovy added
474      * the option to org.codehaus.groovy.control.CompilerConfiguration and used it in
475      * org.codehaus.groovy.classgen.asm.WriterController.
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 }