/*
* Copyright, Aspect Security, Inc.
*
* This file is part of JavaSnoop.
*
* JavaSnoop is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* JavaSnoop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with JavaSnoop. If not, see <http://www.gnu.org/licenses/>.
*/
package com.aspect.snoop.util;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.NotFoundException;
public class ReflectionUtil {
private static final Class[] PRIMITIVE_CLASSES = {
Boolean.class,
Byte.class,
Character.class,
Short.class,
Integer.class,
Long.class,
String.class, // not really a primitive but there is a default editor for it in the table
Double.class,
Float.class,
boolean.class,
byte.class,
int.class,
char.class,
short.class,
int.class,
long.class,
double.class,
float.class
};
public static Map<String,String> primitiveArrayMap;
public static boolean isPrimitiveClassName(String cls) {
if ( primitiveArrayMap.get(cls) != null ) {
return true;
}
String prims[] = { "boolean", "char", "byte", "short", "int", "long", "double", "float" };
for( String s : prims ) {
if ( s.equals(cls) ) {
return true;
}
}
return false;
}
static {
primitiveArrayMap = new HashMap<String,String>();
primitiveArrayMap.put("[Z", "boolean[]");
primitiveArrayMap.put("[B", "byte[]");
primitiveArrayMap.put("[C", "char[]");
primitiveArrayMap.put("[S", "short[]");
primitiveArrayMap.put("[I", "int[]");
primitiveArrayMap.put("[J", "long[]");
primitiveArrayMap.put("[D", "double[]");
primitiveArrayMap.put("[F", "float[]");
}
public static final int LANGUAGE_MODIFIERS =
Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE |
Modifier.ABSTRACT | Modifier.STATIC | Modifier.FINAL |
Modifier.SYNCHRONIZED | Modifier.NATIVE;
public static String getMethodDescription(Member member) {
StringBuilder desc = new StringBuilder("");
String returnType = null;
String methodName = null;
Class[] params = null;
if ( !(member instanceof Method) && !(member instanceof Constructor) ) {
return member.toString();
}
//String modifiers = Modifier.toString(m.getModifiers() & LANGUAGE_MODIFIERS);
Method m = null;
Constructor c = null;
if ( member instanceof Method ) {
m = (Method)member;
returnType = ReflectionUtil.getSimpleClassName(m.getReturnType().getName());
methodName = m.getName();
params = m.getParameterTypes();
} else {
c = (Constructor)member;
returnType = "void";
methodName = "<init>";
params = c.getParameterTypes();
}
desc.append(returnType);
desc.append(" ");
desc.append(methodName);
desc.append("(");
for (int i = 0; i < params.length; i++) {
String className = ReflectionUtil.getSimpleClassName(params[i].getName());
desc.append(className);
if (i != params.length - 1) {
desc.append(",");
}
}
desc.append(")");
return desc.toString();
}
/*
public static String getMethodDescription(UniqueMethod m) {
StringBuilder desc = new StringBuilder("");
desc.append(m.getName() + "(");
String[] params = m.getParameterTypes();
for (int i = 0; i < params.length; i++) {
String className = ReflectionUtil.getSimpleClassName(params[i]);
desc.append(className);
if (i != params.length - 1) {
desc.append(",");
}
}
desc.append(")");
return desc.toString();
}*/
public static Field getAccessibleField(Object o, String s) throws Exception {
Field f = o.getClass().getDeclaredField(s);
f.setAccessible(true);
return f;
}
public static Field getAccessibleField(Object o, Field f) {
f.setAccessible(true);
return f;
}
public static String getStringValue(Object o, String fieldName) throws Exception {
Field f = getAccessibleField(o, fieldName);
return (String) f.get(o);
}
public static Object getAsStringValue(Object o, String fieldName) throws Exception {
Field f = getAccessibleField(o, fieldName);
return f.get(o).toString();
}
public static Class[] getClassArrayValue(Object wrappedObj, String s) throws Exception {
Field f = getAccessibleField(wrappedObj, s);
return (Class[]) f.get(wrappedObj);
}
public static Object[] getObjectArrayValue(Object wrappedObj, String s) throws Exception {
Field f = getAccessibleField(wrappedObj, s);
return (Object[]) f.get(wrappedObj);
}
public static String getSimpleClassName(String name) {
String cls = name.substring(name.lastIndexOf(".") + 1);
if ( cls.startsWith("[")) {
String primArray = primitiveArrayMap.get(name);
if ( primArray != null ) {
return primArray;
}
} else if ( cls.endsWith(";") ) {
cls = cls.substring(0,cls.length()-1) + "[]";
}
return cls;
}
public static String getPackageFromClass(String cls) {
int lastDot = cls.lastIndexOf(".");
if ( lastDot == -1 ) {
return "";
}
return cls.substring(0,lastDot);
}
public static List<Field> getAllPrimitiveFields(Object o) {
List<Field> primitiveFields = new ArrayList<Field>();
Field[] fields = o.getClass().getDeclaredFields();
List<Field> allFields = new ArrayList<Field>();
allFields.addAll( Arrays.asList(fields) );
Class cls = o.getClass();
while( (cls = cls.getSuperclass()) != null && ! cls.getClass().equals(Object.class) ) {
allFields.addAll( Arrays.asList(cls.getDeclaredFields()) );
}
for (Field f : allFields) {
int mod = f.getModifiers();
if ( Modifier.isStatic(mod) ) {
continue;
}
f.setAccessible(true);
for (Class c : PRIMITIVE_CLASSES) {
try {
if (f.getType().equals(c)) {
primitiveFields.add(f);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
return primitiveFields;
}
public static List<Field> getAllNonPrimitiveFields(Object o) {
List<Field> nonPrimitiveFields = new ArrayList<Field>();
Field[] fields = o.getClass().getDeclaredFields();
List<Field> allFields = new ArrayList<Field>();
allFields.addAll( Arrays.asList(fields) );
Class cls = o.getClass();
while( (cls = cls.getSuperclass()) != null && ! cls.getClass().equals(Object.class) ) {
allFields.addAll( Arrays.asList(cls.getDeclaredFields()) );
}
for (Field f : allFields) {
f.setAccessible(true);
int mod = f.getModifiers();
if ( Modifier.isStatic(mod) || f.isSynthetic() ) {
continue;
}
boolean isPrimitive = false;
try {
for (Class c : PRIMITIVE_CLASSES) {
if (f.getType().equals(c)) {
isPrimitive = true;
}
}
if (!isPrimitive) {
nonPrimitiveFields.add(f);
}
} catch (Exception e) {
e.printStackTrace();
}
}
return nonPrimitiveFields;
}
public static boolean isBoolean(Field f) {
return f.getType().equals(boolean.class) || f.getType().equals(Boolean.class);
}
public static boolean isString(Field f) {
return f.getType().equals(String.class);
}
public static boolean getBooleanValue(Object o, String fieldName) throws Exception {
Field f = getAccessibleField(o, fieldName);
return ((Boolean) f.get(o)).booleanValue();
}
public static boolean isShort(Field f) {
return f.getType().equals(short.class) || f.getType().equals(Short.class);
}
public static short getShortValue(Object o, String fieldName) throws Exception {
Field f = getAccessibleField(o, fieldName);
return ((Short) f.get(o)).shortValue();
}
public static boolean isInteger(Field f) {
return f.getType().equals(int.class) || f.getType().equals(Integer.class);
}
public static int getIntegerValue(Object o, String fieldName) throws Exception {
Field f = getAccessibleField(o, fieldName);
return ((Integer) f.get(o)).intValue();
}
public static boolean isLong(Field f) {
return f.getType().equals(long.class) || f.getType().equals(Long.class);
}
public static long getLongValue(Object o, String fieldName) throws Exception {
Field f = getAccessibleField(o, fieldName);
return ((Long) f.get(o)).longValue();
}
public static boolean isFloat(Field f) {
return f.getType().equals(float.class) || f.getType().equals(Float.class);
}
public static boolean hasMainClass(Class c) {
try {
Method m = c.getDeclaredMethod("main", new String[]{}.getClass());
return true;
} catch (NoSuchMethodException e) {
}
return false;
}
public static boolean hasMainClass(CtClass c) {
try {
CtClass[] params = new CtClass[1];
params[0] = ClassPool.getDefault().get(new String[]{}.getClass().getName());
CtMethod m = c.getDeclaredMethod("main", params);
return true;
} catch (NotFoundException e) { }
return false;
}
public static boolean hasMainClass(CtClass c, ClassPool cp) {
try {
CtClass[] params = new CtClass[1];
params[0] = cp.get(new String[]{}.getClass().getName());
CtMethod m = c.getDeclaredMethod("main", params);
return true;
} catch (NotFoundException e) { }
return false;
}
public static boolean isInterfaceOrAbstract(Class c) {
int modifier = c.getModifiers();
return Modifier.isAbstract(modifier) || Modifier.isInterface(modifier);
}
public static Class[] getParameterTypes(AccessibleObject method) {
if ( method instanceof Method )
return ((Method)method).getParameterTypes();
else if ( method instanceof Constructor )
return ((Constructor)method).getParameterTypes();
throw new IllegalArgumentException("Expected method or constructor");
}
public static Class getDeclaringClass(AccessibleObject method) {
if ( method instanceof Method )
return ((Method)method).getDeclaringClass();
else if ( method instanceof Constructor )
return ((Constructor)method).getDeclaringClass();
throw new IllegalArgumentException("Expected method or constructor");
}
public static String getMethodName(AccessibleObject method) {
if ( method instanceof Method )
return ((Method)method).getName();
else if ( method instanceof Constructor )
return ((Constructor)method).getName();
throw new IllegalArgumentException("Expected method or constructor");
}
public static boolean isInterfaceOrAbstract(AccessibleObject method) {
if ( method instanceof Method )
return Modifier.isAbstract(((Method)method).getModifiers());
else if ( method instanceof Constructor )
return Modifier.isAbstract(((Constructor)method).getModifiers());
throw new IllegalArgumentException("Expected method or constructor");
}
public static Class getReturnType(AccessibleObject method) {
if ( method instanceof Method )
return ((Method)method).getReturnType();
else if ( method instanceof Constructor )
return Void.class;
throw new IllegalArgumentException("Expected method or constructor");
}
public float getFloatValue(Object o, String fieldName) throws Exception {
Field f = getAccessibleField(o, fieldName);
return ((Float) f.get(o)).floatValue();
}
public static boolean isDouble(Field f) {
return f.getType().equals(double.class) || f.getType().equals(Double.class);
}
public static double getDoubleValue(Object o, String fieldName) throws Exception {
Field f = getAccessibleField(o, fieldName);
return ((Double) f.get(o)).doubleValue();
}
public static boolean isCharacter(Field f) {
return f.getType().equals(char.class) || f.getType().equals(Character.class);
}
public static char getCharacterValue(Object o, String fieldName) throws Exception {
Field f = getAccessibleField(o, fieldName);
return ((Character) f.get(o)).charValue();
}
public static boolean isByte(Field f) {
return f.getType().equals(byte.class) || f.getType().equals(Byte.class);
}
public static byte getByteValue(Object o, String fieldName) throws Exception {
Field f = getAccessibleField(o, fieldName);
return ((Byte) f.get(o)).byteValue();
}
public static boolean isPrimitiveButNotArray(Object o) {
for (Class c : PRIMITIVE_CLASSES) {
if (c.equals(o.getClass())) {
return true;
}
}
return false;
}
public static boolean isPrimitive(Object o) {
for (Class c : PRIMITIVE_CLASSES) {
if (c.equals(o.getClass())) {
return true;
}
}
String clsName = o.getClass().getName();
if ( primitiveArrayMap.get(clsName) != null ) {
return true;
}
return false;
}
public static boolean isSerializable(Object object) {
ObjectOutputStream oos = null;
try {
if (ReflectionUtil.isPrimitive(object)) {
return true;
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(baos);
oos.writeObject(object);
oos.close();
return baos.toByteArray().length > 0;
} catch (IOException ex) {
return false;
}
}
public static Object getObjectFrom(Object o) {
return o;
}
public static Object getObjectFrom(byte b) {
return new Byte(b);
}
public static Object getObjectFrom(boolean b) {
return new Boolean(b);
}
public static Object getObjectFrom(char c) {
return new Character(c);
}
public static Object getObjectFrom(short s) {
return new Short(s);
}
public static Object getObjectFrom(int i) {
return new Integer(i);
}
public static Object getObjectFrom(long l) {
return new Long(l);
}
public static Object getObjectFrom(double d) {
return new Double(d);
}
public static Object getObjectFrom(float f) {
return new Float(f);
}
}