/*
* Copyright 2013 LinkedIn Corp. All rights reserved
*
* 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 com.linkedin.databus2.test;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.apache.log4j.Logger;
/**
* The class is used to introspect all member variables of a class (private, public, protected).
*/
public class ClassIntrospectionUtils
{
public static final Logger LOG = Logger.getLogger(ClassIntrospectionUtils.class.getName());
Object _classInstance;
Class<?> _classType;
/**
* The constructor to use introspection utils on a particular class
* @param classInstance Instance of the particular class you want to introspect
*/
public ClassIntrospectionUtils(Object classInstance)
{
_classInstance = classInstance;
_classType = classInstance.getClass();
}
// ==================== Setter and getter method specific to the instance of the class ==============================
/**
* Get the value of the field from the class.
* @param fieldName The name of the field
* @param fieldClassType Class type to which the return value is cast
* @param <T>
* @return
* @throws NoSuchFieldException
* @throws IllegalAccessException
*/
public<T> T getFieldValue(String fieldName, Class<T> fieldClassType)
throws NoSuchFieldException, IllegalAccessException
{
Field field = getField(fieldName);
Object value = field.get(_classInstance);
return fieldClassType.cast(value);
}
/**
* Set the value of the field which is not accessible[private]
* @param fieldName The name of the field to be set
* @param fieldValue Value to set for the field
* @throws NoSuchFieldException
* @throws IllegalAccessException
*/
public void setFieldValue(String fieldName, Object fieldValue)
throws NoSuchFieldException, IllegalAccessException
{
getField(fieldName).set(_classInstance, fieldValue);
}
/**
* Invoke any method (including private) of the class using this method.
* @param methodName The method name that needs to be invoked
* @param args The parameters that are needed for the invokation of the method
*/
public Object invokeMethod(String methodName, Object... args)
throws NoSuchMethodException, InvocationTargetException, IllegalAccessException
{
Method method = getMethod(methodName);
return method.invoke(_classInstance,args);
}
//=================== Getter and setter method for the class type (not the instance) ================================
/**
* Get access to the method for future invocations. The method changes the visibility of private members as well.
* Get the 'Method' (Java type Method, not the actual field from the instance).
* @param methodName The name of the method
* @return
* @throws NoSuchMethodException
*/
public Method getMethod(String methodName)
throws NoSuchMethodException
{
return methodUnwinder(methodName,_classType);
}
/**
* Get the 'Field' (Java type Field, not the actual field from the instance).
* @param fieldName The name of the field whose visibility is to be changed
* @return
* @throws NoSuchFieldException
*/
public Field getField(String fieldName)
throws NoSuchFieldException
{
return fieldUnwinder(fieldName, _classType);
}
//==================================== Helper methods for the introspection class ===================================
/**
* Recursively goes through the class's hierarchy to search for the particular field
*/
private static<T> Field fieldUnwinder(String fieldName, Class<T> classType)
throws NoSuchFieldException
{
Field field = null;
if(LOG.isDebugEnabled())
LOG.debug("Peeking into classInstance: " + classType);
try
{
field = classType.getDeclaredField(fieldName);
}
catch (NoSuchFieldException e)
{
//If the field does not exist, let's check if it exists in the parent class.
Class<?> superClass = classType.getSuperclass();
if(superClass == null)
throw e;
return fieldUnwinder(fieldName, superClass);
}
field.setAccessible(true);
return field;
}
/**
* Recursively goes through the class's hierarchy to search for the particular method
*/
private<T> Method methodUnwinder(String fieldName, Class<T> classType)
throws NoSuchMethodException
{
Method method= null;
if(LOG.isDebugEnabled())
LOG.debug("Peeking into classInstance: " + classType);
try
{
method = classType.getDeclaredMethod(fieldName);
}
catch (NoSuchMethodException e)
{
//If the field does not exist, let's check if it exists in the parent class.
Class<?> superClass = classType.getSuperclass();
if(superClass == null)
throw e;
return methodUnwinder(fieldName, superClass);
}
method.setAccessible(true);
return method;
}
}