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