The accessedByReflection Statement
The ZKM Script accessedByReflection statement allows you to specify which classes, fields or methods are accessed by Java Reflection API calls.
It has an effect only if your ZKM Script obfuscate statement has specified autoReflectionHandling=normal .
Successive accessedByReflection statements have a cumulative effect. Once a specification has been set its effect can be
If there is no accessedByReflection statement in effect then all classes, fields and methods are considered to be possibly accessed by Reflection.
That is, no accessedByReflection statement is the same as an accessedByReflection statement which specifies all classes, fields and methods.
If your ZKM Script obfuscate statement uses the autoReflectionHandling=normal setting,
then it is highly recommended that you precede it with an accessedByReflection statement which specifies just those classes, fields and methods which
are actually accessed by Reflection via calls which have not been fully resolved by Zelix KlassMaster.
The remainder of this page is organized into the following sections.
accessedByReflection statement parameters may be loosely categorized into the following groups
Put informally (with mandatory components in bold), the syntax is:
<classAnnotations> <classModifiers> "<archiveQualifier>"!<packageQualifiers>.<className> <containingClause> <extendsClause> <implementsClause>;
For a class to be matched by the statement, 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 matched.
- 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 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 exclude parameter then
a final "^" tag after the class name specification causes the enclosing class to be matched.
If a class exclusion parameter's class name specification is followed by
a "+" tag then the parameter also causes the names of all the fields and methods of the class to be matched.
accessedByReflection * and //Match all classes in the default package
*.Class1 and //Match all classes with the unqualified class name "Class1"
public !final *.* and //Match all public non-final classes
package abstract *.C*s extends pack1.Class1 and
//Match all "public abstract" classes that
//have an unqualified name matching "C*s" and extend "pack1.Class1".
p*.* and //Match all classes in packages that start with the character "p"
//Match all classes with the unqualified class name "Class1" also exclude all fields and methods of those classes
*.* Class2 + and
//Match all classes with a name that start with "Class" except for "Class0" and "Class1"
*.(Class* && !(Class0 || Class1)) and
"MyJar*.jar"!*.* and //exclude all classes contained in a JAR file with a name matching "MyJar*.jar"
@*.MyAnnotation0 *.*; //Match all classes annotated which an annotation matching *.MyAnnotation0
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 matched by the statement, all of the following must be true:
- Its containing class must match any class exclude parameter component (see Class exclude 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 matched.
- 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.
accessedByReflection *.* * and //Match all fields
*.Class1 !transient int f* and //Match all non-transient "int" fields matching "f*"
//in classes with the unqualified name "Class1"
public *.*^ public volatile * and //Match all "public volatile" fields in
//public classes.
//Also match the containing class.
*.* @*.MyAnnotation0 *; //Match all fields annotated with a class matching *.MyAnnotation0.
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 matched by the statement, all of the following must be true:
- Its containing class must match any class exclude parameter component (see Class exclude 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 matched.
- 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 exclude parameter's throw clause.
So, if the exclude parameter's throws clause is
throws java.io.IOException then the method
must throw java.io.IOException or one of its subclasses to be matched.
accessedByReflection *.* *(*) and //Match all methods
*.* !static m*() and //Match all non-static methods taking no parameters with names matching "m*"
*.* public <init>() and //Match all public no argument constructors
//Match all "native" methods. Also match the containing class.
*.*^ native *(*) and
*.* *(*) throws java.io.IOException and //Match all methods that throw java.io.IOException.
//Match all "abstract" methods that take a single String.
*.* abstract *(java.lang.String) and
//Match all methods in pack1.Class1 along with the matching methods' return and parameter types
pack1.Class1 *(*) +signatureClasses and
//Match all the methods of any class implementing "Serializable" in a package that matches "pack1.*"
pack1.* implements java.io.Serializable *(*) and
//Match all methods annotated with a class matching *.MyAnnotation0.
*.* @*.MyAnnotation0 *(*);
"accessedByReflection" excludeParameter ("and" excludeParameter)* ";"
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" "}"
excludeParameter ::=
|
classExcludeParameter
|
|
|
|
fieldExcludeParameter
|
|
|
|
methodExcludeParameter
|
|
extendsClause ::= "extends" [annotationSpecifier] wildcardClassName
fieldExcludeParameter ::=
classExcludeParameter [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)* ")"
methodExcludeParameter ::=
classExcludeParameter [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
|