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