Zelix KlassMaster - Documentation

The fixedClasses Statement

The ZKM Script fixedClasses statement ensures that specified classes are effectively insulated from the major effects of any subsequent Zelix KlassMaster™ trim or obfuscate statements. The effect is that a "fixed" class produced by Zelix KlassMaster can be replaced with the original class file without effecting the obfuscated application. This effect is useful in scenarios where particular classes may be recompiled automatically at runtime replacing the class produced by Zelix KlassMaster. This can happen with JSP servlets.

Note that the specified classes may still be changed slightly. For example some debugging information can be removed. More significantly, inner class and generics information can still be removed. This information is generally only used by compilers and debuggers so this would typically not be a problem. However, you can prevent the removal of inner class and generics information from effecting your fixed classes by specifying "keepInnerClassInfo=ifNameNotObfuscated" and "keepGenericsInfo=true" on your obfuscate statement.

For each class matched by the statement, Zelix KlassMaster™ will
  • add name exclusions for
    • the fully qualified names of the class, its direct superclass and its directly implemented interfaces
    • the names of every field and method contained in the class
    • the names of any other class, field or method referred to by the class
  • add a flow obfuscation exclusion
  • add a String encryption exclusion

Successive fixedClasses statements (in the same script) have a cumulative effect. Once a fixed class has been specified the only way to remove the specification is with a resetFixedClasses statement.

If the ZKM_FIXED_TOTALLY_UNCHANGED configuration option is specified then the specified class will be copied across completely unchanged.

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

Explanation and Examples

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

For a class to be treated as a fixed class, 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
fixedClasses pack2.Class1 and //Treat class pack2.Class1 as a fixed class
             pack3.* and //Treat all classes in package "pack3" as fixed classes
             //Treat all classes contained in a JAR file with a name matching "MyJar*.jar" as fixed classes
             "MyJar*.jar"!*.* and 
             //Treat all classes annotated which an annotation matching *.MyAnnotation0 as fixed classes
             @*.MyAnnotation0 *.*; 


"fixedClasses" classExcludeParameter ("and" classExcludeParameter )* ";"

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

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

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

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 resetExistingSerializedClasses statement The ZKM Script Language ZKM Script resetFixedClasses statement