ml.shifu.guagua.util.ClassUtils Maven / Gradle / Ivy
The newest version!
/*
* Copyright [2013-2014] PayPal Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ml.shifu.guagua.util;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* A helper class for java reflection.
*/
public final class ClassUtils {
private ClassUtils() {
}
/**
* Only support constructors with no parameters.
*/
public static final Class>[] EMPTY_CLASS_ARRAY = new Class[] {};
/**
* This map is used for cache pairs
*/
private static final Map, Constructor>> CONSTRUCTOR_CACHE = new ConcurrentHashMap, Constructor>>();
/**
* This map is used for cache pairs
*/
private static final Map FIELD_CACHE = new ConcurrentHashMap();
/**
* This map is used for cache pairs. Only first method will be cached here, make
* sure no same method name for such cache.
*/
private static final Map METHOD_CACHE = new ConcurrentHashMap();
/**
* Given a class instance, return all fields, including fields in super classes.
*/
@SuppressWarnings("unchecked")
public static List getAllFields(Class> clazz) {
if(clazz == null || clazz.equals(Object.class)) {
return Collections.EMPTY_LIST;
}
List result = new ArrayList();
for(Field field: clazz.getDeclaredFields()) {
result.add(field);
}
Class> tmpClazz = clazz.getSuperclass();
while(!Object.class.equals(tmpClazz)) {
result.addAll(getAllFields(tmpClazz));
tmpClazz = tmpClazz.getSuperclass();
}
return result;
}
/**
* Given a class instance, return all methods, including methods in super classes.
*/
@SuppressWarnings("unchecked")
public static List getAllMethods(Class> clazz) {
if(clazz == null) {
return Collections.EMPTY_LIST;
}
if(clazz.equals(Object.class)) {
return Collections.EMPTY_LIST;
}
List result = new ArrayList();
for(Method method: clazz.getDeclaredMethods()) {
result.add(method);
}
Class> tmpClazz = clazz.getSuperclass();
while(!Object.class.equals(tmpClazz)) {
result.addAll(getAllMethods(tmpClazz));
tmpClazz = tmpClazz.getSuperclass();
}
return result;
}
/**
* Create an object for the given class. The class should have constructor without any parameters.
*
* @param clazz
* class of which an object is created
* @return a new object
* @throws RuntimeException
* In case any exception for reflection.
*/
public static T newInstance(Class clazz) {
T result;
try {
@SuppressWarnings("unchecked")
Constructor meth = (Constructor) CONSTRUCTOR_CACHE.get(clazz);
if(meth == null) {
meth = clazz.getDeclaredConstructor(EMPTY_CLASS_ARRAY);
meth.setAccessible(true);
CONSTRUCTOR_CACHE.put(clazz, meth);
}
result = meth.newInstance();
} catch (Exception e) {
throw new RuntimeException(e);
}
return result;
}
/**
* Create an object for the given class. The class should have constructor without any parameters.
*
* @param clazz
* class of which an object is created
* @param parameterClasses
* the parameter classes used for constructor
* @param parameters
* the parameters used for new instance
* @return a new object
* @throws RuntimeException
* In case any exception for reflection.
*/
public static T newInstance(Class clazz, Class>[] parameterClasses, Object[] parameters) {
T result;
try {
@SuppressWarnings("unchecked")
Constructor meth = (Constructor) CONSTRUCTOR_CACHE.get(clazz);
if(meth == null) {
meth = clazz.getDeclaredConstructor(parameterClasses);
meth.setAccessible(true);
CONSTRUCTOR_CACHE.put(clazz, meth);
}
result = meth.newInstance(parameters);
} catch (Exception e) {
throw new RuntimeException(e);
}
return result;
}
/**
* Get declared field given field name including fields in super classes. If no field get, return null.
*/
public static Field getDeclaredFieldIncludeSuper(String fieldName, Class> clazz) {
String key = clazz.getName() + "#" + fieldName;
Field cacheField = FIELD_CACHE.get(key);
if(cacheField != null) {
return cacheField;
}
for(Field field: ClassUtils.getAllFields(clazz)) {
if(field.getName().equals(fieldName)) {
return field;
}
}
return null;
}
/**
* Return declared method with empty parameter.
*/
public static Method getDeclaredMethod(String methodName, Class> clazz) throws NoSuchMethodException {
String key = clazz.getName() + "#" + methodName;
Method cacheMethod = METHOD_CACHE.get(key);
if(cacheMethod != null) {
return cacheMethod;
}
return clazz.getDeclaredMethod(methodName, ClassUtils.EMPTY_CLASS_ARRAY);
}
/**
* Iterate all methods including methods in super class, return the first one; if no method with such name, return
* null.
*/
public static Method getFirstMethodWithName(String name, Class> clazz) {
String key = clazz.getName() + "#" + name;
Method cacheMethod = METHOD_CACHE.get(key);
if(cacheMethod != null) {
return cacheMethod;
}
List allMethods = ClassUtils.getAllMethods(clazz);
Method method = null;
for(Method f: allMethods) {
if(f.getName().equals(name)) {
method = f;
break;
}
}
return method;
}
private static void setFieldValue(Field field, Object instance, Object value) throws IllegalArgumentException,
IllegalAccessException {
field.setAccessible(true);
field.set(instance, value);
}
private static Object getFieldValue(Field field, Object instance) throws IllegalArgumentException,
IllegalAccessException {
field.setAccessible(true);
return field.get(instance);
}
/**
* Set filed value according to field name, class instance, object instance and field value. All exceptions are
* wrapped as RuntimeException.
*
* @throws RuntimeException
* wraps any exception as root cause.
*/
public static void setFieldValue(String fieldName, Class> clazz, Object instance, Object value) {
try {
Field field = getDeclaredFieldIncludeSuper(fieldName, clazz);
setFieldValue(field, instance, value);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* Return field value according to field name, class, instance.All exceptions are wrapped as RuntimeException.
*
* @throws RuntimeException
* wraps any exception as root cause.
*/
public static Object getFieldValue(String fieldName, Class> clazz, Object instance) {
try {
Field field = getDeclaredFieldIncludeSuper(fieldName, clazz);
return getFieldValue(field, instance);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* Call method through java reflection.
*
* @throws RuntimeException
* wraps any exception as root cause.
*/
public static Object invokeMethod(Method method, Object instance, Object... parameters) {
try {
method.setAccessible(true);
return method.invoke(instance, parameters);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* Call method through java reflection. TODO getFirstMethodWithName should be changed by finding method with method
* name and parameter types.
*
* @throws RuntimeException
* wraps any exception as root cause.
*/
public static Object invokeMethod(String name, Class> clazz, Object instance, Object... parameters) {
try {
Method method = getFirstMethodWithName(name, clazz);
method.setAccessible(true);
return method.invoke(instance, parameters);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}