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