package com.laytonsmith.PureUtilities.ClassLoading.ClassMirror;
import com.laytonsmith.PureUtilities.Common.StringUtils;
import java.io.Serializable;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import org.objectweb.asm.Opcodes;
/**
* This is a mirror for the {@link java.lang.reflect.Modifier} class.
* This provides is* methods for all the modifiers, instead of requiring
* bitwise logic to determine if various modifiers are present.
*/
public class ModifierMirror implements Serializable {
private static final long serialVersionUID = 1L;
private final int access;
private int modifiers = 0;
/**
* This is the canonical order of modifiers, used in the toString method.
*/
private static transient final Object[] order = new Object[]{
Modifier.PUBLIC, "public",
Modifier.PRIVATE, "private",
Modifier.PROTECTED, "protected",
Modifier.STATIC, "static",
Modifier.FINAL, "final",
Modifier.SYNCHRONIZED, "synchronized",
Modifier.VOLATILE, "volatile",
Modifier.TRANSIENT, "transient",
Modifier.NATIVE, "native",
Modifier.INTERFACE, "interface",
Modifier.ABSTRACT, "abstract",
Modifier.STRICT, "strictfp"};
/**
* This constructor is used when mirroring an already loaded class. The modifier
* is just the modifier returned by Class.
* @param modifier
*/
public ModifierMirror(int modifier){
this.access = 0;
this.modifiers = modifier;
}
/**
* Creates a new ModifierMirror. Type is needed to determine which flags are applicable, and access
* is the access modifier stored with the class file.
* @param type Since asm encodes the parameters slightly differently for various types, the type must also be provided.
* @param access
*/
public ModifierMirror(Type type, int access) {
this.access = access;
//public, private, protected, final are all valid on all three types
if(type == Type.CLASS || type == Type.METHOD || type == Type.FIELD){
if (hasFlag(Opcodes.ACC_PRIVATE)) {
modifiers |= Modifier.PRIVATE;
}
if (hasFlag(Opcodes.ACC_PROTECTED)) {
modifiers |= Modifier.PROTECTED;
}
if (hasFlag(Opcodes.ACC_PUBLIC)) {
modifiers |= Modifier.PUBLIC;
}
if (hasFlag(Opcodes.ACC_FINAL)) {
modifiers |= Modifier.FINAL;
}
}
//static is only valid on fields and methods
if (type == Type.FIELD || type == Type.METHOD){
if(hasFlag(Opcodes.ACC_STATIC)) {
modifiers |= Modifier.STATIC;
}
}
//interface is only valid on a class
if(type == Type.CLASS){
if (hasFlag(Opcodes.ACC_INTERFACE)) {
modifiers |= Modifier.INTERFACE;
}
}
//abstract is only valid on classes or methods
if(type == Type.CLASS || type == Type.METHOD){
if (hasFlag(Opcodes.ACC_ABSTRACT)) {
modifiers |= Modifier.ABSTRACT;
}
}
//native, strict, and synchronized are only valid on methods
if(type == Type.METHOD){
if (hasFlag(Opcodes.ACC_NATIVE)) {
modifiers |= Modifier.NATIVE;
}
if (hasFlag(Opcodes.ACC_STRICT)) {
modifiers |= Modifier.STRICT;
}
if (hasFlag(Opcodes.ACC_SYNCHRONIZED)) {
modifiers |= Modifier.SYNCHRONIZED;
}
}
//transient and volatile are only valid on fields
if(type == Type.FIELD){
if (hasFlag(Opcodes.ACC_TRANSIENT)) {
modifiers |= Modifier.TRANSIENT;
}
if (hasFlag(Opcodes.ACC_VOLATILE)) {
modifiers |= Modifier.VOLATILE;
}
}
}
private boolean hasFlag(int flag) {
return (access & flag) > 0;
}
/**
* Returns true if the abstract modifier was present.
* @return
*/
public boolean isAbstract() {
return (modifiers & Modifier.ABSTRACT) > 0;
}
/**
* Returns true if the final modifier was present
* @return
*/
public boolean isFinal() {
return (modifiers & Modifier.FINAL) > 0;
}
/**
* Returns true if the class is an interface
* @return
*/
public boolean isInterface() {
return (modifiers & Modifier.ABSTRACT) > 0;
}
/**
* Returns true if the native modifier was present
* @return
*/
public boolean isNative() {
return (modifiers & Modifier.NATIVE) > 0;
}
/**
* Returns true if the private modifier was present
* @return
*/
public boolean isPrivate() {
return (modifiers & Modifier.PRIVATE) > 0;
}
/**
* Returns true if the protected modifier was present
* @return
*/
public boolean isProtected() {
return (modifiers & Modifier.PROTECTED) > 0;
}
/**
* Returns true if the public modifier was present
* @return
*/
public boolean isPublic() {
return (modifiers & Modifier.PUBLIC) > 0;
}
/**
* Returns true if this is package private, that is,
* it is not public, private, or protected. No access
* modifier is present, rather this is the lack of
* the other three modifiers.
* @return
*/
public boolean isPackagePrivate(){
return !(
isPrivate()
|| isProtected()
|| isPublic()
);
}
/**
* Returns true if the static modifier was present
* @return
*/
public boolean isStatic() {
return (modifiers & Modifier.STATIC) > 0;
}
/**
* Returns true if the strictfp modifier was present
* @return
*/
public boolean isStrict() {
return (modifiers & Modifier.STRICT) > 0;
}
/**
* Returns true if the synchronized modifier was present
* @return
*/
public boolean isSynchronized() {
return (modifiers & Modifier.SYNCHRONIZED) > 0;
}
/**
* Returns true if the transient modifier was present
* @return
*/
public boolean isTransient() {
return (modifiers & Modifier.TRANSIENT) > 0;
}
/**
* Returns true if the volatile modifier was present
* @return
*/
public boolean isVolatile() {
return (modifiers & Modifier.VOLATILE) > 0;
}
/**
* Returns an int compatible with the {@link java.lang.reflect.Modifier}
* class.
* @return
*/
public int getModifiers() {
return modifiers;
}
@Override
public String toString() {
List<String> build = new ArrayList<String>();
for (int i = 0; i < order.length; i++) {
int type = (Integer) order[i];
String name = (String) order[++i];
if ((modifiers & type) > 0) {
build.add(name);
}
}
return StringUtils.Join(build, " ");
}
public static enum Type{
CLASS, METHOD, FIELD;
}
}