Zelix KlassMaster - Documentation
 

The trimUnexclude Statement

The ZKM Script trimUnexclude statement acts only on the set of excluded objects created by a trimExclude statement. The statement removes the specified objects from the set of excluded objects so that they become available once more to be removed from the bytecode by the ZKM Script trim statement.

The trimUnexclude statement is intended to be used in conjunction with a trimExclude statement to specify a final set of excluded objects that would have been difficult to achieve using a trimExclude statement alone. Typically, in such cases, an initial trimExclude statement would set the broad exclusions and then the trimUnexclude statement would specify the exceptions to those broad exclusions.

Successive trimUnexclude statements have a cumulative effect. The effect of all trim exclusions and unexclusions that have been set is removed by a resetTrimExclusions statement.

The remainder of this page is organized into the following sections.

Examples and Explanation

trimUnexclude statement parameters may be loosely categorized into the following groups

Class unexclude parameters

Put informally (with mandatory components in bold), the syntax is:
<classAnnotations> <classModifiers> "<archiveQualifier>"!<packageQualifiers>.<className> <containingClause> <extendsClause> <implementsClause>;

For a class to be unexcluded, all of the following must be true:
  • Its annotations must match any specified annotations.
  • Its modifiers (e.g. public final) must match all parameter modifiers. So if the parameters are public abstract !interface then the class must be public, abstract and NOT an interface to be unexcluded.
  • If the parameter has an archive qualifier then the class must be contained in an archive which matches that archive qualifier.
  • Its package qualifiers must match any specified package unexclude parameter component. If there is no package unexclude parameter component then the class must be in the default package.
  • Its unqualified name must match the specified class name specification.
  • If the parameter has a containing clause then the class must contain members which match the specified class
  • If the parameter has an extends clause then the class must be a subclass of the specified class
  • If the parameter has an implements clause then the class must directly or indirectly implement all of the specified interfaces
If the class parameter is a component of a field or method unexclude parameter then a final "^" tag after the class name specification causes the enclosing class to be unexcluded as well.
trimUnexclude *          and         //unexclude all classes in the default package
              *.Class1   and         //unexclude all classes with the unqualified class name "Class1"
              public !final *.* and  //unexclude all public non-final classes
              package abstract *.C*s extends pack1.Class1 and 
                           //unexclude all "public abstract" classes that
                           //have an unqualified name matching "C*s" and extend "pack1.Class1".
              p*.*     and //unexclude all classes in packages that start with the character "p"
              //unexclude all classes with a name that start with "Class" except for "Class0" and "Class1"
              *.(Class* && !(Class0 || Class1)) and 
              "MyJar*.jar"!*.* and //unexclude all classes contained in a JAR file with a name matching "MyJar*.jar"
              @*.MyAnnotation0 *.*;  //unexclude all classes annotated which an annotation matching *.MyAnnotation0
                          

Field unexclude parameters

Put informally (with mandatory components in bold), the syntax is:
<classAnnotations> <classModifiers> "<archiveQualifier>"!<packageQualifiers>.<className> <extendsClause> <implementsClause>
    <fieldAnnotations> <fieldModifiers> <fieldType> <fieldName>;

For a field to be unexcluded, all of the following must be true:
  • Its containing class must match any class unexclude parameter component (see Class unexclude parameters).
  • Its annotations must match any specified field level annotations.
  • Its modifiers (e.g. public volatile) must match all parameter field modifiers. So if the parameters are public static !transient then the field must be public, static and NOT transient to be unexcluded.
  • Its type (e.g. int[] or java.lang.String) must match the parameter field type if it exists.
  • Its name must match the parameter field name.
trimUnexclude *.* *  and //unexclude all fields
              //unexclude all non-transient "int" fields matching "f*" in classes with the unqualified name "Class1"
              *.Class1 !transient int f* and 
              //unexclude all "public volatile" fields in public classes. Also unexclude the containing class.
              public *.*^ public volatile * and 
              *.* @*.MyAnnotation0 *;  //Exclude all fields annotated with a class matching *.MyAnnotation0.

Method unexclude parameters

Put informally (with mandatory components in bold), the syntax is:
<classAnnotations> <classModifiers> "<archiveQualifier>"!<packageQualifiers>.<className> <extendsClause> <implementsClause>
    <methodAnnotations> <methodModifiers> <methodName>(<argumentTypes>) <throwsClause> +signatureClasses;

For a method to be unexcluded, all of the following must be true:
  • Its containing class must match any class unexclude parameter component (see Class unexclude parameters).
  • Its annotations must match any specified method or method parameter level annotations.
  • Its modifiers (e.g. public native) must match all parameter method modifiers. So if the parameters are public static !synchronized then the method must be public, static and NOT synchronized to be unexcluded.
  • Its name must match the parameter method name.
  • Its argument types (e.g. int[], java.lang.String) must match the parameter argument types if they exist. (A single parameter argument type of "*" matches any method argument types including no arguments.) If the parameter has no argument type then the method must take no arguments.
  • Its throws clause must contain all the classes specified in the unexclude parameter's throw clause. So, if the unexclude parameter's throws clause is throws java.io.IOException then the method must throw java.io.IOException or one of its subclasses to be unexcluded.

The trimUnexclude statement supports the special method names <init> and <clinit> which represent constructor and class initializer method names respectively. However, class initializers are automatically excluded from being trimmed in any case.
trimUnexclude *.* *(*)           and  //unexclude all methods
              *.* public <init>() and  //unexclude all public no argument constructor
              *.* !static m*()   and  //unexclude all non-static methods taking no parameters with names matching "m*"
              //unexclude all "native" methods. Also unexclude the containing class.
              *.*^ native *(*)  and  
              *.* *(*) throws java.io.IOException and  //unexclude all methods that throw java.io.IOException.
              //Unexclude all "abstract" methods that take a single String.
              *.* abstract *(java.lang.String) and 
              //Unexclude all methods in pack1.Class1 along with the matching methods' return and parameter types
              pack1.Class1 *(*) +signatureClasses and 
              //Unexclude all the methods of any class implementing "Serializable" in a package that matches "pack1.*"
              pack1.* implements java.io.Serializable *(*) and 
              //Exclude all methods annotated with a class matching *.MyAnnotation0.
              *.* @*.MyAnnotation0 *(*);

Annotation unexclude parameters

Put informally (with mandatory components in bold), the syntax is: @<className>

An annotation unexclude parameter is fundamentally different from the Class unexclude, Field unexclude and Method unexclude parameters discussed above. An annotation unexclude parameter tells Zelix KlassMaster™ to unexclude specified annotations on classes, fields or methods that have been specified by an annnotation exclude parameter appearing in an associated trimExclude statement .

trimUnexclude @pack0.AnnotationClass0 and //Don't remove any pack0.AnnotationClass0 annotations
              @*.MyAnnotation1; //Don't remove any annotations matching *.MyAnnotation1

Syntax

"trimUnexclude" unexcludeParameter ("and" unexcludeParameter)* ";"

annotationUnexcludeParameter ::= "@" wildcardClassName

annotationSpecifier ::= ("@" [packageExcludeParameter] nameSpecifier) | annotationSpecifierAndList

annotationSpecifierAndList ::= ["!"] "(" annotationSpecifierOrList ("&&" annotationSpecifierOrList)* ")"

annotationSpecifierOrList ::= annotationSpecifier ("||" annotationSpecifier)*

classUnexcludeParameter ::=
   [annotationSpecifier] [["!"] "public" | "package"]
   [["!"] "abstract"] [["!"] "final"] [["!"] "interface"] [["!"] "synthetic"] [["!"] "enum"] [["!"] "annotation"]
   [["!"] "abstract"] [["!"] "final"] [["!"] "interface"]
   ["\"" archiveQualifier "\"" "!"] [packageExcludeParameter ["."]] nameSpecifier ["^"] ["+"] [containingClause]
   [extendsClause] [implementsClause]

containingClause ::= "containing" "{" "memberAndList" "}"

unexcludeParameter ::= classUnexcludeParameter |
fieldUnexcludeParameter |
methodUnexcludeParameter |
annotationUnexcludeParameter

extendsClause ::= "extends" [annotationSpecifier] wildcardClassName

fieldUnexcludeParameter ::=
   classUnexcludeParameter [annotationSpecifier] [["!"] "public" | "protected"| "package"| "private"]
   [["!"] "static"] [["!"] "final"] [["!"] "transient"] [["!"] "volatile"] [["!"] "synthetic"] [["!"] "enum"]
   [type] nameSpecifier

fullyQualifiedClassName ::= name ("." name)*

implementsClause ::= "implements" [annotationSpecifier] wildcardClassName ("," [annotationSpecifier] wildcardClassName)*

memberAndList ::= ["!"] "(" memberOrList ("&&" memberOrList)* ")"

memberOrList ::= memberSpecifier ("||" memberSpecifier)*

memberSpecifier ::= fieldExcludeParameter | methodExcludeParameter

nameAndList ::= ["!"] "(" nameOrList ("&&" nameOrList)* ")"

methodUnexcludeParameter ::=
   classUnexcludeParameter [annotationSpecifier] [["!"] "public" | "protected"| "package"| "private"]
   [["!"] "abstract"] [["!"] "static"] [["!"] "final"] [["!"] "native"] [["!"] "synchronized"] [["!"] "synthetic"] [["!"] "bridge"]
   nameSpecifier "(" [ "*" | (parameter ("," parameter)*)] ")" ["throws" wildcardClassName]

name ::= (["0"-"9","a"-"z","A"-"Z","$","_"])+
   i.e. a Java identifer (e.g. a package, class, field or method name) with no wildcards allowed

nameAndList ::= ["!"] "(" nameOrList ("&&" nameOrList)* ")"

nameOrList ::= nameSpecifier ("||" nameSpecifier)*

nameSpecifier ::= wildcardName | nameAndList

packageExcludeParameter ::= packageName | packageNameAndList

packageName ::= wildcardName ("." wildcardName)* "."
   NB: the final "." is part of the package name

packageNameAndList ::= ["!"] "(" packageNameOrList ("&&" packageNameOrList)* ")"

packageNameOrList ::= packageExcludeParameter ("||" packageExcludeParameter)*

parameter ::= [annotationSpecifier] ("*" | "?" | type)

type ::=
   ("byte" | "short" | "char" | "int" | "long" | "float" | "double"| "boolean" |
   fullyQualifiedClassName) ("[]")*

wildcardClassName ::= wildcardName ("." wildcardName)*

wildcardName ::= (["*","0"-"9","a"-"z","A"-"Z","$","_"])+
   i.e. a Java identifer (e.g. a package, class, field or method name) with the "*" wildcard allowed
Where archiveQualifier is a relative or absolute archive path name with the "*" wildcard allowed. E.g. "/lib/*.jar" or "myJar0.jar"

ZKM Script trimExclude statement The ZKM Script Language ZKM Script resetTrimExclusions statement
Zelix KlassMaster - Java Obfuscator