Zelix KlassMaster - Documentation

The groupings Statement

Zelix KlassMaster's™ flow obfuscation functionality (initiated through the obfuscate statement) needs to know how classes will be grouped at runtime. This knowledge allows it to avoid creating any inappropriate interdependencies between classes. It will not create an interdependency across groupings.

Normally, Zelix KlassMaster™ assumes that the groupings implicit in the JAR files from which the classes were opened specify the groupings that will exist at runtime. However, in some environments this may not be enough because
  • the JAR structure from which the classes are loaded does not reflect the runtime JAR structure or
  • there are implicit groupings within a JAR file. That is, in certain scenarios (eg. certain runtime classpath settings), only a subset of the classes within a JAR file can be accessed.
The ZKM Script groupings statement allows you to specify groupings in addition to those implicit in the JAR files.

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


The groupings statement consists of a series of class specifications separated by the and keyword grouped inside of curly brackets (ie. "{...}"). Informally (with mandatory components in bold), the syntax for a class specification is:
<classAnnotations> <classModifiers> "<archiveQualifier>"!<packageQualifiers>.<className> <containingClause> <extendsClause> <implementsClause>;

For a class to match a class specification, 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 excluded.
  • 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 exclude parameter component. If there is no package exclude parameter component then the class must be in the default package.
  • Its unqualified name must match the parameter's class name specifier.
  • 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


groupings {pack1.* and pack2.*} //Classes in packages pack1 and pack2
          //Classes in package pack3 and all classes annotated which an annotation matching *.MyAnnotation0
          //form the 2nd grouping
          {pack3.* and @*.MyAnnotation0 *.*};
groupings {pack1.* and pack.*.*} //Classes in package pack1 and its subpackages
          {pack3.!(Class1)} //Classes in package pack3 except Class1
          {pack3.Class1}; //Class pack3.Class1 forms its own one class grouping


"groupings" (grouping)+ ";"

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

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

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

grouping ::= "{" classExcludeParameter ("and" classExcludeParameter )* "}"

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

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

extendsClause ::= "extends" [annotationSpecifier] wildcardClassName

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

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

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

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

memberSpecifier ::= fieldExcludeParameter | methodExcludeParameter

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

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)*

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 resetFixedClasses statement The ZKM Script Language ZKM Script resetGroupings statement
Zelix KlassMaster - Java Obfuscator