• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * ProGuard -- shrinking, optimization, obfuscation, and preverification
3  *             of Java bytecode.
4  *
5  * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published by the Free
9  * Software Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * This program is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15  * more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20  */
21 package proguard.gradle;
22 
23 import groovy.lang.Closure;
24 import org.gradle.api.DefaultTask;
25 import org.gradle.api.file.*;
26 import org.gradle.api.logging.*;
27 import org.gradle.api.tasks.*;
28 import proguard.*;
29 import proguard.classfile.*;
30 import proguard.classfile.util.ClassUtil;
31 import proguard.util.ListUtil;
32 
33 import java.io.*;
34 import java.util.ArrayList;
35 import java.util.Iterator;
36 import java.util.List;
37 import java.util.Map;
38 import java.util.StringTokenizer;
39 
40 /**
41  * This Task allows to configure and run ProGuard from Gradle.
42  *
43  * @author Eric Lafortune
44  */
45 public class ProGuardTask extends DefaultTask
46 {
47     // Accumulated input and output, for the sake of Gradle's lazy file
48     // resolution and lazy task execution.
49     private final List          inJarFiles         = new ArrayList();
50     private final List          inJarFilters       = new ArrayList();
51     private final List          outJarFiles        = new ArrayList();
52     private final List          outJarFilters      = new ArrayList();
53     private final List          inJarCounts        = new ArrayList();
54     private final List          libraryJarFiles    = new ArrayList();
55     private final List          libraryJarFilters  = new ArrayList();
56     private final List          configurationFiles = new ArrayList();
57 
58     // Accumulated configuration.
59     private final Configuration configuration      = new Configuration();
60 
61     // Field acting as a parameter for the class member specification methods.
62     private ClassSpecification classSpecification;
63 
64 
65     // Gradle task inputs and outputs, because annotations on the List fields
66     // (private or not) don't seem to work. Private methods don't work either,
67     // but package visible or protected methods are ok.
68 
69     @InputFiles
getInJarFileCollection()70     protected FileCollection getInJarFileCollection()
71     {
72         return getProject().files(inJarFiles);
73     }
74 
75     @Optional @OutputFiles
getOutJarFileCollection()76     protected FileCollection getOutJarFileCollection()
77     {
78         return getProject().files(outJarFiles);
79     }
80 
81     @InputFiles
getLibraryJarFileCollection()82     protected FileCollection getLibraryJarFileCollection()
83     {
84         return getProject().files(libraryJarFiles);
85     }
86 
87     @InputFiles
getConfigurationFileCollection()88     protected FileCollection getConfigurationFileCollection()
89     {
90         return getProject().files(configurationFiles);
91     }
92 
93 
94     // Convenience methods to retrieve settings from outside the task.
95 
96     /**
97      * Returns the collected list of input files (directory, jar, aar, etc,
98      * represented as Object, String, File, etc).
99      */
getInJarFiles()100     public List getInJarFiles()
101     {
102         return inJarFiles;
103     }
104 
105     /**
106      * Returns the collected list of filters (represented as argument Maps)
107      * corresponding to the list of input files.
108      */
getInJarFilters()109     public List getInJarFilters()
110     {
111         return inJarFilters;
112     }
113 
114     /**
115      * Returns the collected list of output files (directory, jar, aar, etc,
116      * represented as Object, String, File, etc).
117      */
getOutJarFiles()118     public List getOutJarFiles()
119     {
120         return outJarFiles;
121     }
122 
123     /**
124      * Returns the collected list of filters (represented as argument Maps)
125      * corresponding to the list of output files.
126      */
getOutJarFilters()127     public List getOutJarFilters()
128     {
129         return outJarFilters;
130     }
131 
132     /**
133      * Returns the list with the numbers of input files that correspond to the
134      * list of output files.
135      *
136      * For instance, [2, 3] means that
137      *   the contents of the first 2 input files go to the first output file and
138      *   the contents of the next 3 input files go to the second output file.
139      */
getInJarCounts()140     public List getInJarCounts()
141     {
142         return inJarCounts;
143     }
144 
145     /**
146      * Returns the collected list of library files (directory, jar, aar, etc,
147      * represented as Object, String, File, etc).
148      */
getLibraryJarFiles()149     public List getLibraryJarFiles()
150     {
151         return libraryJarFiles;
152     }
153 
154     /**
155      * Returns the collected list of filters (represented as argument Maps)
156      * corresponding to the list of library files.
157      */
getLibraryJarFilters()158     public List getLibraryJarFilters()
159     {
160         return libraryJarFilters;
161     }
162 
163     /**
164      * Returns the collected list of configuration files to be included
165      * (represented as Object, String, File, etc).
166      */
getConfigurationFiles()167     public List getConfigurationFiles()
168     {
169         return configurationFiles;
170     }
171 
172 
173     // Gradle task settings corresponding to all ProGuard options.
174 
configuration(Object configurationFiles)175     public void configuration(Object configurationFiles)
176     throws ParseException, IOException
177     {
178         // Just collect the arguments, so they can be resolved lazily.
179         this.configurationFiles.add(configurationFiles);
180     }
181 
injars(Object inJarFiles)182     public void injars(Object inJarFiles)
183     throws ParseException
184     {
185         injars(null, inJarFiles);
186     }
187 
injars(Map filterArgs, Object inJarFiles)188     public void injars(Map filterArgs, Object inJarFiles)
189     throws ParseException
190     {
191         // Just collect the arguments, so they can be resolved lazily.
192         this.inJarFiles.add(inJarFiles);
193         this.inJarFilters.add(filterArgs);
194     }
195 
outjars(Object outJarFiles)196     public void outjars(Object outJarFiles)
197     throws ParseException
198     {
199         outjars(null, outJarFiles);
200     }
201 
outjars(Map filterArgs, Object outJarFiles)202     public void outjars(Map filterArgs, Object outJarFiles)
203     throws ParseException
204     {
205         // Just collect the arguments, so they can be resolved lazily.
206         this.outJarFiles.add(outJarFiles);
207         this.outJarFilters.add(filterArgs);
208         this.inJarCounts.add(Integer.valueOf(inJarFiles.size()));
209     }
210 
libraryjars(Object libraryJarFiles)211     public void libraryjars(Object libraryJarFiles)
212     throws ParseException
213     {
214         libraryjars(null, libraryJarFiles);
215     }
216 
libraryjars(Map filterArgs, Object libraryJarFiles)217     public void libraryjars(Map filterArgs, Object libraryJarFiles)
218     throws ParseException
219     {
220         // Just collect the arguments, so they can be resolved lazily.
221         this.libraryJarFiles.add(libraryJarFiles);
222         this.libraryJarFilters.add(filterArgs);
223     }
224 
225     // Hack: support the keyword without parentheses in Groovy.
getskipnonpubliclibraryclasses()226     public Object getskipnonpubliclibraryclasses()
227     {
228         skipnonpubliclibraryclasses();
229         return null;
230     }
231 
skipnonpubliclibraryclasses()232     public void skipnonpubliclibraryclasses()
233     {
234         configuration.skipNonPublicLibraryClasses = true;
235     }
236 
237     // Hack: support the keyword without parentheses in Groovy.
getdontskipnonpubliclibraryclassmembers()238     public Object getdontskipnonpubliclibraryclassmembers()
239     {
240         dontskipnonpubliclibraryclassmembers();
241         return null;
242     }
243 
dontskipnonpubliclibraryclassmembers()244     public void dontskipnonpubliclibraryclassmembers()
245     {
246         configuration.skipNonPublicLibraryClassMembers = false;
247     }
248 
249     // Hack: support the keyword without parentheses in Groovy.
getkeepdirectories()250     public Object getkeepdirectories()
251     {
252         keepdirectories();
253         return null;
254     }
255 
keepdirectories()256     public void keepdirectories()
257     {
258         keepdirectories(null);
259     }
260 
keepdirectories(String filter)261     public void keepdirectories(String filter)
262     {
263         configuration.keepDirectories =
264             extendFilter(configuration.keepDirectories, filter);
265     }
266 
target(String targetClassVersion)267     public void target(String targetClassVersion)
268     {
269         configuration.targetClassVersion =
270             ClassUtil.internalClassVersion(targetClassVersion);
271     }
272 
273     // Hack: support the keyword without parentheses in Groovy.
getforceprocessing()274     public Object getforceprocessing()
275     {
276         forceprocessing();
277         return null;
278     }
279 
forceprocessing()280     public void forceprocessing()
281     {
282         configuration.lastModified = Long.MAX_VALUE;
283     }
284 
keep(String classSpecificationString)285     public void keep(String classSpecificationString)
286     throws ParseException
287     {
288         keep(null, classSpecificationString);
289     }
290 
keep(Map keepArgs, String classSpecificationString)291     public void keep(Map    keepArgs,
292                      String classSpecificationString)
293     throws ParseException
294     {
295         configuration.keep =
296             extendClassSpecifications(configuration.keep,
297             createKeepClassSpecification(false,
298                                          true,
299                                          false,
300                                          keepArgs,
301                                          classSpecificationString));
302     }
303 
keep(Map keepClassSpecificationArgs)304     public void keep(Map keepClassSpecificationArgs)
305     throws ParseException
306     {
307         keep(keepClassSpecificationArgs, (Closure)null);
308     }
309 
keep(Map keepClassSpecificationArgs, Closure classMembersClosure)310     public void keep(Map     keepClassSpecificationArgs,
311                      Closure classMembersClosure)
312     throws ParseException
313     {
314         configuration.keep =
315             extendClassSpecifications(configuration.keep,
316             createKeepClassSpecification(false,
317                                          true,
318                                          false,
319                                          keepClassSpecificationArgs,
320                                          classMembersClosure));
321     }
322 
keepclassmembers(String classSpecificationString)323     public void keepclassmembers(String classSpecificationString)
324     throws ParseException
325     {
326         keepclassmembers(null, classSpecificationString);
327     }
328 
keepclassmembers(Map keepArgs, String classSpecificationString)329     public void keepclassmembers(Map    keepArgs,
330                                  String classSpecificationString)
331     throws ParseException
332     {
333         configuration.keep =
334             extendClassSpecifications(configuration.keep,
335             createKeepClassSpecification(false,
336                                          false,
337                                          false,
338                                          keepArgs,
339                                          classSpecificationString));
340     }
341 
keepclassmembers(Map keepClassSpecificationArgs)342     public void keepclassmembers(Map keepClassSpecificationArgs)
343     throws ParseException
344     {
345         keepclassmembers(keepClassSpecificationArgs, (Closure)null);
346     }
347 
keepclassmembers(Map keepClassSpecificationArgs, Closure classMembersClosure)348     public void keepclassmembers(Map     keepClassSpecificationArgs,
349                                  Closure classMembersClosure)
350     throws ParseException
351     {
352         configuration.keep =
353             extendClassSpecifications(configuration.keep,
354             createKeepClassSpecification(false,
355                                          false,
356                                          false,
357                                          keepClassSpecificationArgs,
358                                          classMembersClosure));
359     }
360 
keepclasseswithmembers(String classSpecificationString)361     public void keepclasseswithmembers(String classSpecificationString)
362     throws ParseException
363     {
364         keepclasseswithmembers(null, classSpecificationString);
365     }
366 
keepclasseswithmembers(Map keepArgs, String classSpecificationString)367     public void keepclasseswithmembers(Map    keepArgs,
368                                        String classSpecificationString)
369     throws ParseException
370     {
371         configuration.keep =
372             extendClassSpecifications(configuration.keep,
373             createKeepClassSpecification(false,
374                                          false,
375                                          true,
376                                          keepArgs,
377                                          classSpecificationString));
378     }
379 
keepclasseswithmembers(Map keepClassSpecificationArgs)380     public void keepclasseswithmembers(Map keepClassSpecificationArgs)
381     throws ParseException
382     {
383         keepclasseswithmembers(keepClassSpecificationArgs, (Closure)null);
384     }
385 
keepclasseswithmembers(Map keepClassSpecificationArgs, Closure classMembersClosure)386     public void keepclasseswithmembers(Map     keepClassSpecificationArgs,
387                                        Closure classMembersClosure)
388     throws ParseException
389     {
390         configuration.keep =
391             extendClassSpecifications(configuration.keep,
392             createKeepClassSpecification(false,
393                                          false,
394                                          true,
395                                          keepClassSpecificationArgs,
396                                          classMembersClosure));
397     }
398 
keepnames(String classSpecificationString)399     public void keepnames(String classSpecificationString)
400     throws ParseException
401     {
402         keepnames(null, classSpecificationString);
403     }
404 
keepnames(Map keepArgs, String classSpecificationString)405     public void keepnames(Map    keepArgs,
406                           String classSpecificationString)
407     throws ParseException
408     {
409         configuration.keep =
410             extendClassSpecifications(configuration.keep,
411             createKeepClassSpecification(true,
412                                          true,
413                                          false,
414                                          keepArgs,
415                                          classSpecificationString));
416     }
417 
keepnames(Map keepClassSpecificationArgs)418     public void keepnames(Map keepClassSpecificationArgs)
419     throws ParseException
420     {
421         keepnames(keepClassSpecificationArgs, (Closure)null);
422     }
423 
keepnames(Map keepClassSpecificationArgs, Closure classMembersClosure)424     public void keepnames(Map     keepClassSpecificationArgs,
425                           Closure classMembersClosure)
426     throws ParseException
427     {
428         configuration.keep =
429             extendClassSpecifications(configuration.keep,
430             createKeepClassSpecification(true,
431                                          true,
432                                          false,
433                                          keepClassSpecificationArgs,
434                                          classMembersClosure));
435     }
436 
keepclassmembernames(String classSpecificationString)437     public void keepclassmembernames(String classSpecificationString)
438     throws ParseException
439     {
440         keepclassmembernames(null, classSpecificationString);
441     }
442 
keepclassmembernames(Map keepArgs, String classSpecificationString)443     public void keepclassmembernames(Map    keepArgs,
444                                      String classSpecificationString)
445     throws ParseException
446     {
447         configuration.keep =
448             extendClassSpecifications(configuration.keep,
449             createKeepClassSpecification(true,
450                                          false,
451                                          false,
452                                          keepArgs,
453                                          classSpecificationString));
454     }
455 
keepclassmembernames(Map keepClassSpecificationArgs)456     public void keepclassmembernames(Map keepClassSpecificationArgs)
457     throws ParseException
458     {
459         keepclassmembernames(keepClassSpecificationArgs, (Closure)null);
460     }
461 
keepclassmembernames(Map keepClassSpecificationArgs, Closure classMembersClosure)462     public void keepclassmembernames(Map     keepClassSpecificationArgs,
463                                      Closure classMembersClosure)
464     throws ParseException
465     {
466         configuration.keep =
467             extendClassSpecifications(configuration.keep,
468             createKeepClassSpecification(true,
469                                          false,
470                                          false,
471                                          keepClassSpecificationArgs,
472                                          classMembersClosure));
473     }
474 
keepclasseswithmembernames(String classSpecificationString)475     public void keepclasseswithmembernames(String classSpecificationString)
476     throws ParseException
477     {
478         keepclasseswithmembernames(null, classSpecificationString);
479     }
480 
keepclasseswithmembernames(Map keepArgs, String classSpecificationString)481     public void keepclasseswithmembernames(Map    keepArgs,
482                                            String classSpecificationString)
483     throws ParseException
484     {
485         configuration.keep =
486             extendClassSpecifications(configuration.keep,
487             createKeepClassSpecification(true,
488                                          false,
489                                          true,
490                                          keepArgs,
491                                          classSpecificationString));
492     }
493 
keepclasseswithmembernames(Map keepClassSpecificationArgs)494     public void keepclasseswithmembernames(Map keepClassSpecificationArgs)
495     throws ParseException
496     {
497         keepclasseswithmembernames(keepClassSpecificationArgs, (Closure)null);
498     }
499 
keepclasseswithmembernames(Map keepClassSpecificationArgs, Closure classMembersClosure)500     public void keepclasseswithmembernames(Map     keepClassSpecificationArgs,
501                                            Closure classMembersClosure)
502     throws ParseException
503     {
504         configuration.keep =
505             extendClassSpecifications(configuration.keep,
506             createKeepClassSpecification(true,
507                                          false,
508                                          true,
509                                          keepClassSpecificationArgs,
510                                          classMembersClosure));
511     }
512 
513     // Hack: support the keyword without parentheses in Groovy.
getprintseeds()514     public Object getprintseeds()
515     {
516         printseeds();
517         return null;
518     }
519 
printseeds()520     public void printseeds()
521     {
522         configuration.printSeeds = Configuration.STD_OUT;
523     }
524 
printseeds(Object printSeeds)525     public void printseeds(Object printSeeds)
526     throws ParseException
527     {
528         configuration.printSeeds = getProject().file(printSeeds);
529     }
530 
531     // Hack: support the keyword without parentheses in Groovy.
getdontshrink()532     public Object getdontshrink()
533     {
534         dontshrink();
535         return null;
536     }
537 
dontshrink()538     public void dontshrink()
539     {
540         configuration.shrink = false;
541     }
542 
543     // Hack: support the keyword without parentheses in Groovy.
getprintusage()544     public Object getprintusage()
545     {
546         printusage();
547         return null;
548     }
549 
printusage()550     public void printusage()
551     {
552         configuration.printUsage = Configuration.STD_OUT;
553     }
554 
printusage(Object printUsage)555     public void printusage(Object printUsage)
556     throws ParseException
557     {
558         configuration.printUsage = getProject().file(printUsage);
559     }
560 
whyareyoukeeping(String classSpecificationString)561     public void whyareyoukeeping(String classSpecificationString)
562     throws ParseException
563     {
564         configuration.whyAreYouKeeping =
565             extendClassSpecifications(configuration.whyAreYouKeeping,
566                                       createClassSpecification(classSpecificationString));
567     }
568 
whyareyoukeeping(Map classSpecificationArgs)569     public void whyareyoukeeping(Map classSpecificationArgs)
570     throws ParseException
571     {
572         whyareyoukeeping(classSpecificationArgs, null);
573     }
574 
whyareyoukeeping(Map classSpecificationArgs, Closure classMembersClosure)575     public void whyareyoukeeping(Map     classSpecificationArgs,
576                                  Closure classMembersClosure)
577     throws ParseException
578     {
579         configuration.whyAreYouKeeping =
580             extendClassSpecifications(configuration.whyAreYouKeeping,
581             createClassSpecification(classSpecificationArgs,
582                                      classMembersClosure));
583     }
584 
585     // Hack: support the keyword without parentheses in Groovy.
getdontoptimize()586     public Object getdontoptimize()
587     {
588         dontoptimize();
589         return null;
590     }
591 
dontoptimize()592     public void dontoptimize()
593     {
594         configuration.optimize = false;
595     }
596 
optimizations(String filter)597     public void optimizations(String filter)
598     {
599         configuration.optimizations =
600             extendFilter(configuration.optimizations, filter);
601     }
602 
603 
optimizationpasses(int optimizationPasses)604     public void optimizationpasses(int optimizationPasses)
605     {
606         configuration.optimizationPasses = optimizationPasses;
607     }
608 
assumenosideeffects(String classSpecificationString)609     public void assumenosideeffects(String classSpecificationString)
610     throws ParseException
611     {
612         configuration.assumeNoSideEffects =
613             extendClassSpecifications(configuration.assumeNoSideEffects,
614             createClassSpecification(classSpecificationString));
615     }
616 
assumenosideeffects(Map classSpecificationArgs, Closure classMembersClosure)617     public void assumenosideeffects(Map     classSpecificationArgs,
618                                     Closure classMembersClosure)
619     throws ParseException
620     {
621         configuration.assumeNoSideEffects =
622             extendClassSpecifications(configuration.assumeNoSideEffects,
623             createClassSpecification(classSpecificationArgs,
624                                      classMembersClosure));
625     }
626 
627     // Hack: support the keyword without parentheses in Groovy.
getallowaccessmodification()628     public Object getallowaccessmodification()
629     {
630         allowaccessmodification();
631         return null;
632     }
633 
allowaccessmodification()634     public void allowaccessmodification()
635     {
636         configuration.allowAccessModification = true;
637     }
638 
639     // Hack: support the keyword without parentheses in Groovy.
getmergeinterfacesaggressively()640     public Object getmergeinterfacesaggressively()
641     {
642         mergeinterfacesaggressively();
643         return null;
644     }
645 
mergeinterfacesaggressively()646     public void mergeinterfacesaggressively()
647     {
648         configuration.mergeInterfacesAggressively = true;
649     }
650 
651     // Hack: support the keyword without parentheses in Groovy.
getdontobfuscate()652     public Object getdontobfuscate()
653     {
654         dontobfuscate();
655         return null;
656     }
657 
dontobfuscate()658     public void dontobfuscate()
659     {
660         configuration.obfuscate = false;
661     }
662 
663     // Hack: support the keyword without parentheses in Groovy.
getprintmapping()664     public Object getprintmapping()
665     {
666         printmapping();
667         return null;
668     }
669 
printmapping()670     public void printmapping()
671     {
672         configuration.printMapping = Configuration.STD_OUT;
673     }
674 
printmapping(Object printMapping)675     public void printmapping(Object printMapping)
676     throws ParseException
677     {
678         configuration.printMapping = getProject().file(printMapping);
679     }
680 
applymapping(Object applyMapping)681     public void applymapping(Object applyMapping)
682     throws ParseException
683     {
684         configuration.applyMapping = getProject().file(applyMapping);
685     }
686 
obfuscationdictionary(Object obfuscationDictionary)687     public void obfuscationdictionary(Object obfuscationDictionary)
688     throws ParseException
689     {
690         configuration.obfuscationDictionary =
691             getProject().file(obfuscationDictionary);
692     }
693 
classobfuscationdictionary(Object classObfuscationDictionary)694     public void classobfuscationdictionary(Object classObfuscationDictionary)
695     throws ParseException
696     {
697         configuration.classObfuscationDictionary =
698             getProject().file(classObfuscationDictionary);
699     }
700 
packageobfuscationdictionary(Object packageObfuscationDictionary)701     public void packageobfuscationdictionary(Object packageObfuscationDictionary)
702     throws ParseException
703     {
704         configuration.packageObfuscationDictionary =
705             getProject().file(packageObfuscationDictionary);
706     }
707 
708     // Hack: support the keyword without parentheses in Groovy.
getoverloadaggressively()709     public Object getoverloadaggressively()
710     {
711         overloadaggressively();
712         return null;
713     }
714 
overloadaggressively()715     public void overloadaggressively()
716     {
717         configuration.overloadAggressively = true;
718     }
719 
720     // Hack: support the keyword without parentheses in Groovy.
getuseuniqueclassmembernames()721     public Object getuseuniqueclassmembernames()
722     {
723         useuniqueclassmembernames();
724         return null;
725     }
726 
useuniqueclassmembernames()727     public void useuniqueclassmembernames()
728     {
729         configuration.useUniqueClassMemberNames = true;
730     }
731 
732     // Hack: support the keyword without parentheses in Groovy.
getdontusemixedcaseclassnames()733     public Object getdontusemixedcaseclassnames()
734     {
735         dontusemixedcaseclassnames();
736         return null;
737     }
738 
dontusemixedcaseclassnames()739     public void dontusemixedcaseclassnames()
740     {
741         configuration.useMixedCaseClassNames = false;
742     }
743 
744     // Hack: support the keyword without parentheses in Groovy.
getkeeppackagenames()745     public Object getkeeppackagenames()
746     {
747         keeppackagenames();
748         return null;
749     }
750 
keeppackagenames()751     public void keeppackagenames()
752     {
753         keeppackagenames(null);
754     }
755 
keeppackagenames(String filter)756     public void keeppackagenames(String filter)
757     {
758         configuration.keepPackageNames =
759             extendFilter(configuration.keepPackageNames, filter, true);
760     }
761 
762     // Hack: support the keyword without parentheses in Groovy.
getflattenpackagehierarchy()763     public Object getflattenpackagehierarchy()
764     {
765         flattenpackagehierarchy();
766         return null;
767     }
768 
flattenpackagehierarchy()769     public void flattenpackagehierarchy()
770     {
771         flattenpackagehierarchy("");
772     }
773 
flattenpackagehierarchy(String flattenPackageHierarchy)774     public void flattenpackagehierarchy(String flattenPackageHierarchy)
775     {
776         configuration.flattenPackageHierarchy =
777             ClassUtil.internalClassName(flattenPackageHierarchy);
778     }
779 
780     // Hack: support the keyword without parentheses in Groovy.
getrepackageclasses()781     public Object getrepackageclasses()
782     {
783         repackageclasses();
784         return null;
785     }
786 
repackageclasses()787     public void repackageclasses()
788     {
789         repackageclasses("");
790     }
791 
repackageclasses(String repackageClasses)792     public void repackageclasses(String repackageClasses)
793     {
794         configuration.repackageClasses =
795             ClassUtil.internalClassName(repackageClasses);
796     }
797 
798     // Hack: support the keyword without parentheses in Groovy.
getkeepattributes()799     public Object getkeepattributes()
800     {
801         keepattributes();
802         return null;
803     }
804 
keepattributes()805     public void keepattributes()
806     {
807         keepattributes(null);
808     }
809 
keepattributes(String filter)810     public void keepattributes(String filter)
811     {
812         configuration.keepAttributes =
813             extendFilter(configuration.keepAttributes, filter);
814     }
815 
816     // Hack: support the keyword without parentheses in Groovy.
getkeepparameternames()817     public Object getkeepparameternames()
818     {
819         keepparameternames();
820         return null;
821     }
822 
keepparameternames()823     public void keepparameternames()
824     {
825         configuration.keepParameterNames = true;
826     }
827 
828     // Hack: support the keyword without parentheses in Groovy.
getrenamesourcefileattribute()829     public Object getrenamesourcefileattribute()
830     {
831         renamesourcefileattribute();
832         return null;
833     }
834 
renamesourcefileattribute()835     public void renamesourcefileattribute()
836     {
837         renamesourcefileattribute("");
838     }
839 
renamesourcefileattribute(String newSourceFileAttribute)840     public void renamesourcefileattribute(String newSourceFileAttribute)
841     {
842         configuration.newSourceFileAttribute = newSourceFileAttribute;
843     }
844 
845     // Hack: support the keyword without parentheses in Groovy.
getadaptclassstrings()846     public Object getadaptclassstrings()
847     {
848         adaptclassstrings();
849         return null;
850     }
851 
adaptclassstrings()852     public void adaptclassstrings()
853     {
854         adaptclassstrings(null);
855     }
856 
adaptclassstrings(String filter)857     public void adaptclassstrings(String filter)
858     {
859         configuration.adaptClassStrings =
860             extendFilter(configuration.adaptClassStrings, filter, true);
861     }
862 
863     // Hack: support the keyword without parentheses in Groovy.
getadaptresourcefilenames()864     public Object getadaptresourcefilenames()
865     {
866         adaptresourcefilenames();
867         return null;
868     }
869 
adaptresourcefilenames()870     public void adaptresourcefilenames()
871     {
872         adaptresourcefilenames(null);
873     }
874 
adaptresourcefilenames(String filter)875     public void adaptresourcefilenames(String filter)
876     {
877         configuration.adaptResourceFileNames =
878             extendFilter(configuration.adaptResourceFileNames, filter);
879     }
880 
881     // Hack: support the keyword without parentheses in Groovy.
getadaptresourcefilecontents()882     public Object getadaptresourcefilecontents()
883     {
884         adaptresourcefilecontents();
885         return null;
886     }
887 
adaptresourcefilecontents()888     public void adaptresourcefilecontents()
889     {
890         adaptresourcefilecontents(null);
891     }
892 
adaptresourcefilecontents(String filter)893     public void adaptresourcefilecontents(String filter)
894     {
895         configuration.adaptResourceFileContents =
896             extendFilter(configuration.adaptResourceFileContents, filter);
897     }
898 
899     // Hack: support the keyword without parentheses in Groovy.
getdontpreverify()900     public Object getdontpreverify()
901     {
902         dontpreverify();
903         return null;
904     }
905 
dontpreverify()906     public void dontpreverify()
907     {
908         configuration.preverify = false;
909     }
910 
911     // Hack: support the keyword without parentheses in Groovy.
getmicroedition()912     public Object getmicroedition()
913     {
914         microedition();
915         return null;
916     }
917 
microedition()918     public void microedition()
919     {
920         configuration.microEdition = true;
921     }
922 
923     // Hack: support the keyword without parentheses in Groovy.
getverbose()924     public Object getverbose()
925     {
926         verbose();
927         return null;
928     }
929 
verbose()930     public void verbose()
931     {
932         configuration.verbose = true;
933     }
934 
935     // Hack: support the keyword without parentheses in Groovy.
getdontnote()936     public Object getdontnote()
937     {
938         dontnote();
939         return null;
940     }
941 
dontnote()942     public void dontnote()
943     {
944         dontnote(null);
945     }
946 
dontnote(String filter)947     public void dontnote(String filter)
948     {
949         configuration.note = extendFilter(configuration.note, filter, true);
950     }
951 
952 
953     // Hack: support the keyword without parentheses in Groovy.
getdontwarn()954     public Object getdontwarn()
955     {
956         dontwarn();
957         return null;
958     }
959 
dontwarn()960     public void dontwarn()
961     {
962         dontwarn(null);
963     }
964 
dontwarn(String filter)965     public void dontwarn(String filter)
966     {
967         configuration.warn = extendFilter(configuration.warn, filter, true);
968     }
969 
970 
971     // Hack: support the keyword without parentheses in Groovy.
getignorewarnings()972     public Object getignorewarnings()
973     {
974         ignorewarnings();
975         return null;
976     }
977 
ignorewarnings()978     public void ignorewarnings()
979     {
980         configuration.ignoreWarnings = true;
981     }
982 
983     // Hack: support the keyword without parentheses in Groovy.
getprintconfiguration()984     public Object getprintconfiguration()
985     {
986         printconfiguration();
987         return null;
988     }
989 
printconfiguration()990     public void printconfiguration()
991     {
992         configuration.printConfiguration = Configuration.STD_OUT;
993     }
994 
printconfiguration(Object printConfiguration)995     public void printconfiguration(Object printConfiguration)
996     throws ParseException
997     {
998         configuration.printConfiguration =
999             getProject().file(printConfiguration);
1000     }
1001 
1002     // Hack: support the keyword without parentheses in Groovy.
getdump()1003     public Object getdump()
1004     {
1005         dump();
1006         return null;
1007     }
1008 
dump()1009     public void dump()
1010     {
1011         configuration.dump = Configuration.STD_OUT;
1012     }
1013 
dump(Object dump)1014     public void dump(Object dump)
1015     throws ParseException
1016     {
1017         configuration.dump = getProject().file(dump);
1018     }
1019 
1020 
1021     // Class member methods.
1022 
field(Map memberSpecificationArgs)1023     public void field(Map memberSpecificationArgs)
1024     throws ParseException
1025     {
1026         if (classSpecification == null)
1027         {
1028             throw new IllegalArgumentException("The 'field' method can only be used nested inside a class specification.");
1029         }
1030 
1031         classSpecification.addField(createMemberSpecification(false,
1032                                                               false,
1033                                                               memberSpecificationArgs));
1034     }
1035 
1036 
constructor(Map memberSpecificationArgs)1037     public void constructor(Map memberSpecificationArgs)
1038     throws ParseException
1039     {
1040         if (classSpecification == null)
1041         {
1042             throw new IllegalArgumentException("The 'constructor' method can only be used nested inside a class specification.");
1043         }
1044 
1045         classSpecification.addMethod(createMemberSpecification(true,
1046                                                                true,
1047                                                                memberSpecificationArgs));
1048     }
1049 
1050 
method(Map memberSpecificationArgs)1051     public void method(Map memberSpecificationArgs)
1052     throws ParseException
1053     {
1054         if (classSpecification == null)
1055         {
1056             throw new IllegalArgumentException("The 'method' method can only be used nested inside a class specification.");
1057         }
1058 
1059         classSpecification.addMethod(createMemberSpecification(true,
1060                                                                false,
1061                                                                memberSpecificationArgs));
1062     }
1063 
1064 
1065     // Gradle task execution.
1066 
1067     @TaskAction
proguard()1068     public void proguard()
1069     throws ParseException, IOException
1070     {
1071         // Let the logging manager capture the standard output and errors from
1072         // ProGuard.
1073         LoggingManager loggingManager = getLogging();
1074         loggingManager.captureStandardOutput(LogLevel.INFO);
1075         loggingManager.captureStandardError(LogLevel.WARN);
1076 
1077         // Run ProGuard with the collected configuration.
1078         new ProGuard(getConfiguration()).execute();
1079 
1080     }
1081 
1082 
1083     /**
1084      * Returns the configuration collected so far, resolving files and
1085      * reading included configurations.
1086      */
getConfiguration()1087     private Configuration getConfiguration() throws IOException, ParseException
1088     {
1089         // Weave the input jars and the output jars into a single class path,
1090         // with lazy resolution of the files.
1091         configuration.programJars = new ClassPath();
1092 
1093         int outJarIndex = 0;
1094 
1095         int inJarCount = inJarCounts.size() == 0 ? -1 :
1096                 ((Integer)inJarCounts.get(0)).intValue();
1097 
1098         for (int inJarIndex = 0; inJarIndex < inJarFiles.size(); inJarIndex++)
1099         {
1100             configuration.programJars =
1101                 extendClassPath(configuration.programJars,
1102                                 inJarFiles.get(inJarIndex),
1103                                 (Map)inJarFilters.get(inJarIndex),
1104                                 false);
1105 
1106             while (inJarIndex == inJarCount - 1)
1107             {
1108                 configuration.programJars =
1109                     extendClassPath(configuration.programJars,
1110                                     outJarFiles.get(outJarIndex),
1111                                     (Map)outJarFilters.get(outJarIndex),
1112                                     true);
1113 
1114                 outJarIndex++;
1115 
1116                 inJarCount = inJarCounts.size() == outJarIndex ? -1 :
1117                     ((Integer)inJarCounts.get(outJarIndex)).intValue();
1118             }
1119         }
1120 
1121         // Copy the library jars into a single class path, with lazy resolution
1122         // of the files.
1123         configuration.libraryJars = new ClassPath();
1124 
1125         for (int libraryJarIndex = 0; libraryJarIndex < libraryJarFiles.size(); libraryJarIndex++)
1126         {
1127             configuration.libraryJars =
1128                 extendClassPath(configuration.libraryJars,
1129                                 libraryJarFiles.get(libraryJarIndex),
1130                                 (Map)libraryJarFilters.get(libraryJarIndex),
1131                                 false);
1132         }
1133 
1134         // Lazily apply the external configuration files.
1135         ConfigurableFileCollection fileCollection =
1136             getProject().files(configurationFiles);
1137 
1138         Iterator<File> files = fileCollection.iterator();
1139         while (files.hasNext())
1140         {
1141             ConfigurationParser parser =
1142                 new ConfigurationParser(files.next(), System.getProperties());
1143 
1144             try
1145             {
1146                 parser.parse(configuration);
1147             }
1148             finally
1149             {
1150                 parser.close();
1151             }
1152         }
1153 
1154         // Make sure the code is processed. Gradle has already checked that it
1155         // was necessary.
1156         configuration.lastModified = Long.MAX_VALUE;
1157 
1158         return configuration;
1159     }
1160 
1161 
1162     // Small utility methods.
1163 
1164     /**
1165      * Extends the given class path with the given filtered input or output
1166      * files.
1167      */
extendClassPath(ClassPath classPath, Object files, Map filterArgs, boolean output)1168     private ClassPath extendClassPath(ClassPath classPath,
1169                                       Object    files,
1170                                       Map       filterArgs,
1171                                       boolean   output)
1172     {
1173         ConfigurableFileCollection fileCollection = getProject().files(files);
1174 
1175         if (classPath == null)
1176         {
1177             classPath = new ClassPath();
1178         }
1179 
1180         Iterator fileIterator = fileCollection.iterator();
1181         while (fileIterator.hasNext())
1182         {
1183             File file = (File)fileIterator.next();
1184             if (output || file.exists())
1185             {
1186                 // Create the class path entry.
1187                 ClassPathEntry classPathEntry = new ClassPathEntry(file, output);
1188 
1189                 // Add any filters to the class path entry.
1190                 if (filterArgs != null)
1191                 {
1192                     classPathEntry.setFilter(ListUtil.commaSeparatedList((String)filterArgs.get("filter")));
1193                     classPathEntry.setApkFilter(ListUtil.commaSeparatedList((String)filterArgs.get("apkfilter")));
1194                     classPathEntry.setJarFilter(ListUtil.commaSeparatedList((String)filterArgs.get("jarfilter")));
1195                     classPathEntry.setAarFilter(ListUtil.commaSeparatedList((String)filterArgs.get("aarfilter")));
1196                     classPathEntry.setWarFilter(ListUtil.commaSeparatedList((String)filterArgs.get("warfilter")));
1197                     classPathEntry.setEarFilter(ListUtil.commaSeparatedList((String)filterArgs.get("earfilter")));
1198                     classPathEntry.setZipFilter(ListUtil.commaSeparatedList((String)filterArgs.get("zipfilter")));
1199                 }
1200 
1201                 classPath.add(classPathEntry);
1202             }
1203         }
1204 
1205         return classPath;
1206     }
1207 
1208 
1209     /**
1210      * Creates specifications to keep classes and class members, based on the
1211      * given parameters.
1212      */
createKeepClassSpecification(boolean allowShrinking, boolean markClasses, boolean markConditionally, Map keepArgs, String classSpecificationString)1213     private KeepClassSpecification createKeepClassSpecification(boolean allowShrinking,
1214                                                                 boolean markClasses,
1215                                                                 boolean markConditionally,
1216                                                                 Map     keepArgs,
1217                                                                 String  classSpecificationString)
1218     throws ParseException
1219     {
1220         ClassSpecification classSpecification =
1221             createClassSpecification(classSpecificationString);
1222 
1223         return
1224             createKeepClassSpecification(allowShrinking,
1225                                          markClasses,
1226                                          markConditionally,
1227                                          keepArgs,
1228                                          classSpecification);
1229     }
1230 
1231 
1232     /**
1233      * Creates specifications to keep classes and class members, based on the
1234      * given parameters.
1235      */
createKeepClassSpecification(boolean allowShrinking, boolean markClasses, boolean markConditionally, Map classSpecificationArgs, Closure classMembersClosure)1236     private KeepClassSpecification createKeepClassSpecification(boolean allowShrinking,
1237                                                                 boolean markClasses,
1238                                                                 boolean markConditionally,
1239                                                                 Map     classSpecificationArgs,
1240                                                                 Closure classMembersClosure)
1241     throws ParseException
1242     {
1243         ClassSpecification classSpecification =
1244             createClassSpecification(classSpecificationArgs,
1245                                      classMembersClosure);
1246         return
1247             createKeepClassSpecification(allowShrinking,
1248                                          markClasses,
1249                                          markConditionally,
1250                                          classSpecificationArgs,
1251                                          classSpecification);
1252     }
1253 
1254 
1255     /**
1256      * Creates specifications to keep classes and class members, based on the
1257      * given parameters.
1258      */
createKeepClassSpecification(boolean allowShrinking, boolean markClasses, boolean markConditionally, Map keepArgs, ClassSpecification classSpecification)1259     private KeepClassSpecification createKeepClassSpecification(boolean            allowShrinking,
1260                                                                 boolean            markClasses,
1261                                                                 boolean            markConditionally,
1262                                                                 Map                keepArgs,
1263                                                                 ClassSpecification classSpecification)
1264     {
1265         return
1266             new KeepClassSpecification(markClasses,
1267                                        markConditionally,
1268                                        retrieveBoolean(keepArgs, "includedescriptorclasses", false),
1269                                        retrieveBoolean(keepArgs, "allowshrinking",           allowShrinking),
1270                                        retrieveBoolean(keepArgs, "allowoptimization",        false),
1271                                        retrieveBoolean(keepArgs, "allowobfuscation",         false),
1272                                        classSpecification);
1273     }
1274 
1275 
1276     /**
1277      * Creates specifications to keep classes and class members, based on the
1278      * given ProGuard-style class specification.
1279      */
createClassSpecification(String classSpecificationString)1280     private ClassSpecification createClassSpecification(String classSpecificationString)
1281     throws ParseException
1282     {
1283         try
1284         {
1285             ConfigurationParser parser =
1286                 new ConfigurationParser(new String[] { classSpecificationString }, null);
1287 
1288             try
1289             {
1290                 return parser.parseClassSpecificationArguments();
1291             }
1292             finally
1293             {
1294                 parser.close();
1295             }
1296         }
1297         catch (IOException e)
1298         {
1299             throw new ParseException(e.getMessage());
1300         }
1301     }
1302 
1303 
1304     /**
1305      * Creates a specification of classes and class members, based on the
1306      * given parameters.
1307      */
createClassSpecification(Map classSpecificationArgs, Closure classMembersClosure)1308     private ClassSpecification createClassSpecification(Map     classSpecificationArgs,
1309                                                         Closure classMembersClosure)
1310     throws ParseException
1311     {
1312         // Extract the arguments.
1313         String access            = (String)classSpecificationArgs.get("access");
1314         String annotation        = (String)classSpecificationArgs.get("annotation");
1315         String type              = (String)classSpecificationArgs.get("type");
1316         String name              = (String)classSpecificationArgs.get("name");
1317         String extendsAnnotation = (String)classSpecificationArgs.get("extendsannotation");
1318         String extends_          = (String)classSpecificationArgs.get("extends");
1319         if (extends_ == null)
1320         {
1321             extends_             = (String)classSpecificationArgs.get("implements");
1322         }
1323 
1324         // Create the class specification.
1325         ClassSpecification classSpecification =
1326             new ClassSpecification(null,
1327                                    requiredClassAccessFlags(true, access, type),
1328                                    requiredClassAccessFlags(false, access, type),
1329                                    annotation        != null ? ClassUtil.internalType(annotation)        : null,
1330                                    name              != null ? ClassUtil.internalClassName(name)         : null,
1331                                    extendsAnnotation != null ? ClassUtil.internalType(extendsAnnotation) : null,
1332                                    extends_          != null ? ClassUtil.internalClassName(extends_)     : null);
1333 
1334         // Initialize the class specification with its closure.
1335         if (classMembersClosure != null)
1336         {
1337             // Temporarily remember the class specification, so we can add
1338             // class member specifications.
1339             this.classSpecification = classSpecification;
1340             classMembersClosure.call(classSpecification);
1341             this.classSpecification = null;
1342         }
1343 
1344         return classSpecification;
1345     }
1346 
1347 
1348     /**
1349      * Parses the class access flags that must be set (or not), based on the
1350      * given ProGuard-style flag specification.
1351      */
requiredClassAccessFlags(boolean set, String access, String type)1352     private int requiredClassAccessFlags(boolean set,
1353                                          String  access,
1354                                          String  type)
1355     throws ParseException
1356     {
1357         int accessFlags = 0;
1358 
1359         if (access != null)
1360         {
1361             StringTokenizer tokenizer = new StringTokenizer(access, " ,");
1362             while (tokenizer.hasMoreTokens())
1363             {
1364                 String token = tokenizer.nextToken();
1365 
1366                 if (token.startsWith("!") ^ set)
1367                 {
1368                     String strippedToken = token.startsWith("!") ?
1369                         token.substring(1) :
1370                         token;
1371 
1372                     int accessFlag =
1373                         strippedToken.equals(JavaConstants.ACC_PUBLIC)     ? ClassConstants.ACC_PUBLIC      :
1374                         strippedToken.equals(JavaConstants.ACC_FINAL)      ? ClassConstants.ACC_FINAL       :
1375                         strippedToken.equals(JavaConstants.ACC_ABSTRACT)   ? ClassConstants.ACC_ABSTRACT    :
1376                         strippedToken.equals(JavaConstants.ACC_SYNTHETIC)  ? ClassConstants.ACC_SYNTHETIC   :
1377                         strippedToken.equals(JavaConstants.ACC_ANNOTATION) ? ClassConstants.ACC_ANNOTATTION :
1378                                                                              0;
1379 
1380                     if (accessFlag == 0)
1381                     {
1382                         throw new ParseException("Incorrect class access modifier ["+strippedToken+"]");
1383                     }
1384 
1385                     accessFlags |= accessFlag;
1386                 }
1387             }
1388         }
1389 
1390         if (type != null && (type.startsWith("!") ^ set))
1391         {
1392             int accessFlag =
1393                 type.equals("class")                           ? 0                            :
1394                 type.equals(      JavaConstants.ACC_INTERFACE) ||
1395                 type.equals("!" + JavaConstants.ACC_INTERFACE) ? ClassConstants.ACC_INTERFACE :
1396                 type.equals(      JavaConstants.ACC_ENUM)      ||
1397                 type.equals("!" + JavaConstants.ACC_ENUM)      ? ClassConstants.ACC_ENUM      :
1398                                                                  -1;
1399             if (accessFlag == -1)
1400             {
1401                 throw new ParseException("Incorrect class type ["+type+"]");
1402             }
1403 
1404             accessFlags |= accessFlag;
1405         }
1406 
1407         return accessFlags;
1408     }
1409 
1410 
1411     /**
1412      * Creates a specification of class members, based on the given parameters.
1413      */
createMemberSpecification(boolean isMethod, boolean isConstructor, Map classSpecificationArgs)1414     private MemberSpecification createMemberSpecification(boolean isMethod,
1415                                                           boolean isConstructor,
1416                                                           Map     classSpecificationArgs)
1417     throws ParseException
1418     {
1419         // Extract the arguments.
1420         String access            = (String)classSpecificationArgs.get("access");
1421         String type              = (String)classSpecificationArgs.get("type");
1422         String annotation        = (String)classSpecificationArgs.get("annotation");
1423         String name              = (String)classSpecificationArgs.get("name");
1424         String parameters        = (String)classSpecificationArgs.get("parameters");
1425 
1426         // Perform some basic conversions and checks on the attributes.
1427         if (annotation != null)
1428         {
1429             annotation = ClassUtil.internalType(annotation);
1430         }
1431 
1432         if (isMethod)
1433         {
1434             if (isConstructor)
1435             {
1436                 if (type != null)
1437                 {
1438                     throw new ParseException("Type attribute not allowed in constructor specification ["+type+"]");
1439                 }
1440 
1441                 if (parameters != null)
1442                 {
1443                     type = JavaConstants.TYPE_VOID;
1444                 }
1445 
1446                 name = ClassConstants.METHOD_NAME_INIT;
1447             }
1448             else if ((type != null) ^ (parameters != null))
1449             {
1450                 throw new ParseException("Type and parameters attributes must always be present in combination in method specification");
1451             }
1452         }
1453         else
1454         {
1455             if (parameters != null)
1456             {
1457                 throw new ParseException("Parameters attribute not allowed in field specification ["+parameters+"]");
1458             }
1459         }
1460 
1461         List parameterList = ListUtil.commaSeparatedList(parameters);
1462 
1463         String descriptor =
1464             parameters != null ? ClassUtil.internalMethodDescriptor(type, parameterList) :
1465             type       != null ? ClassUtil.internalType(type)                            :
1466                                  null;
1467 
1468         return new MemberSpecification(requiredMemberAccessFlags(true,  access),
1469                                        requiredMemberAccessFlags(false, access),
1470                                        annotation,
1471                                        name,
1472                                        descriptor);
1473     }
1474 
1475 
1476     /**
1477      * Parses the class member access flags that must be set (or not), based on
1478      * the given ProGuard-style flag specification.
1479      */
requiredMemberAccessFlags(boolean set, String access)1480     private int requiredMemberAccessFlags(boolean set,
1481                                           String  access)
1482     throws ParseException
1483     {
1484         int accessFlags = 0;
1485 
1486         if (access != null)
1487         {
1488             StringTokenizer tokenizer = new StringTokenizer(access, " ,");
1489             while (tokenizer.hasMoreTokens())
1490             {
1491                 String token = tokenizer.nextToken();
1492 
1493                 if (token.startsWith("!") ^ set)
1494                 {
1495                     String strippedToken = token.startsWith("!") ?
1496                         token.substring(1) :
1497                         token;
1498 
1499                     int accessFlag =
1500                         strippedToken.equals(JavaConstants.ACC_PUBLIC)       ? ClassConstants.ACC_PUBLIC       :
1501                         strippedToken.equals(JavaConstants.ACC_PRIVATE)      ? ClassConstants.ACC_PRIVATE      :
1502                         strippedToken.equals(JavaConstants.ACC_PROTECTED)    ? ClassConstants.ACC_PROTECTED    :
1503                         strippedToken.equals(JavaConstants.ACC_STATIC)       ? ClassConstants.ACC_STATIC       :
1504                         strippedToken.equals(JavaConstants.ACC_FINAL)        ? ClassConstants.ACC_FINAL        :
1505                         strippedToken.equals(JavaConstants.ACC_SYNCHRONIZED) ? ClassConstants.ACC_SYNCHRONIZED :
1506                         strippedToken.equals(JavaConstants.ACC_VOLATILE)     ? ClassConstants.ACC_VOLATILE     :
1507                         strippedToken.equals(JavaConstants.ACC_TRANSIENT)    ? ClassConstants.ACC_TRANSIENT    :
1508                         strippedToken.equals(JavaConstants.ACC_BRIDGE)       ? ClassConstants.ACC_BRIDGE       :
1509                         strippedToken.equals(JavaConstants.ACC_VARARGS)      ? ClassConstants.ACC_VARARGS      :
1510                         strippedToken.equals(JavaConstants.ACC_NATIVE)       ? ClassConstants.ACC_NATIVE       :
1511                         strippedToken.equals(JavaConstants.ACC_ABSTRACT)     ? ClassConstants.ACC_ABSTRACT     :
1512                         strippedToken.equals(JavaConstants.ACC_STRICT)       ? ClassConstants.ACC_STRICT       :
1513                         strippedToken.equals(JavaConstants.ACC_SYNTHETIC)    ? ClassConstants.ACC_SYNTHETIC    :
1514                                                                                0;
1515 
1516                     if (accessFlag == 0)
1517                     {
1518                         throw new ParseException("Incorrect class member access modifier ["+strippedToken+"]");
1519                     }
1520 
1521                     accessFlags |= accessFlag;
1522                 }
1523             }
1524         }
1525 
1526         return accessFlags;
1527     }
1528 
1529 
1530     /**
1531      * Retrieves a specified boolean flag from the given map.
1532      */
retrieveBoolean(Map args, String name, boolean defaultValue)1533     private boolean retrieveBoolean(Map args, String name, boolean defaultValue)
1534     {
1535         if (args == null)
1536         {
1537             return defaultValue;
1538         }
1539 
1540         Object arg = args.get(name);
1541 
1542         return arg == null ? defaultValue : ((Boolean)arg).booleanValue();
1543     }
1544 
1545 
1546     /**
1547      * Adds the given class specification to the given list, creating a new list
1548      * if necessary.
1549      */
extendClassSpecifications(List classSpecifications, ClassSpecification classSpecification)1550     private List extendClassSpecifications(List               classSpecifications,
1551                                            ClassSpecification classSpecification)
1552     {
1553         if (classSpecifications == null)
1554         {
1555             classSpecifications = new ArrayList();
1556         }
1557 
1558         classSpecifications.add(classSpecification);
1559 
1560         return classSpecifications;
1561     }
1562 
1563 
1564     /**
1565      * Adds the given class specifications to the given list, creating a new
1566      * list if necessary.
1567      */
extendClassSpecifications(List classSpecifications, List additionalClassSpecifications)1568     private List extendClassSpecifications(List classSpecifications,
1569                                            List additionalClassSpecifications)
1570     {
1571         if (additionalClassSpecifications != null)
1572         {
1573             if (classSpecifications == null)
1574             {
1575                 classSpecifications = new ArrayList();
1576             }
1577 
1578             classSpecifications.addAll(additionalClassSpecifications);
1579         }
1580 
1581         return classSpecifications;
1582     }
1583 
1584 
1585     /**
1586      * Adds the given filter to the given list, creating a new list if
1587      * necessary.
1588      */
extendFilter(List filter, String filterString)1589     private List extendFilter(List   filter,
1590                               String filterString)
1591     {
1592         return extendFilter(filter, filterString, false);
1593     }
1594 
1595 
1596     /**
1597      * Adds the given filter to the given list, creating a new list if
1598      * necessary. External class names are converted to internal class names,
1599      * if requested.
1600      */
extendFilter(List filter, String filterString, boolean convertExternalClassNames)1601     private List extendFilter(List    filter,
1602                               String  filterString,
1603                               boolean convertExternalClassNames)
1604     {
1605         if (filter == null)
1606         {
1607             filter = new ArrayList();
1608         }
1609 
1610         if (filterString == null)
1611         {
1612             // Clear the filter to keep all names.
1613             filter.clear();
1614         }
1615         else
1616         {
1617             if (convertExternalClassNames)
1618             {
1619                 filterString = ClassUtil.internalClassName(filterString);
1620             }
1621 
1622             // Append the filter.
1623             filter.addAll(ListUtil.commaSeparatedList(filterString));
1624         }
1625 
1626         return filter;
1627     }
1628 }
1629