An Example
Home ] Up ] Reconstructing a Class ] Inspecting a Class Instance ] Instantiating an Object ] Creating an Array ] Calling a Method ] [ An Example ]

 

 

Here's an example of how you can use reflection to dynamically:

  • Load a class 
  • Create an instance of that class
  • Invoke a method of that class (a static method and an instance method)

First, we have a very simple class that is to be reflected:

package reflectee;

import java.util.Random;

/**
 * A class that is to be reflected.
 * When instantiated, it creates a random integer.
 */
public class ReflectMe
{
  /**
   * Creates a new instance of ReflectMe.
   * (This constructor provided for simple instantiation.)
   */
  public ReflectMe()
  {
    this(DEFAULT_MAX_RANDOM_VALUE);
  }
  
  /**
   * Creates a new instance of ReflectMe
   *
   * @param maxRandomValue -- the random value will be
   *                          between 0 and this value.
   */
  public ReflectMe(int maxRandomValue)
  {
    m_randomValue = new Random().nextInt(maxRandomValue);
  }
  
  /**
   * Gets the random value generated.
   */
  public int getRandomValue()
  {
    return m_randomValue;
  }
  
  /**
   * Sets the random value.
   */
  public void setRandomValue(int value)
  {
    System.out.println("Setting value to " + value);
    m_randomValue = value;
  }
  
  /**
   * Main entry point
   */
  public static void main(String[] args)
  {
    if (args.length < 1)
    {
      System.err.println("Usage: ReflectMe <maxRandomValue>");
    }
    else
    {
      // The following will throw a NumberFormatException
      // if args[0] is not a value integer.
      int maxRandomValue = Integer.parseInt(args[0]);
      System.out.println("Generating random integer < " + maxRandomValue);
      
      ReflectMe me = new ReflectMe(maxRandomValue);
      System.out.println("Random value = " + me.getRandomValue());
    }
  }
  
  //// Private data ////
  private int m_randomValue; // The generated random integer
  private static final int DEFAULT_MAX_RANDOM_VALUE = 100;
}

Now, here's the class that will do the reflection:

package reflector;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

/**
 * Class to use reflection on another class.
 */
public class MyReflector
{
  /**
   * Main entry point.
   *
   * @param args -- arg[0] : the fully qualified class
   *                         name to reflect
   *                arg[1] : the name of the method to run
   *                arg[2] to arg[n] : arguments to pass to the method
   */
  public static void main(String[] args)
  {
    if (args.length < 2)
    {
      System.err.println(
          "Usage: MyReflector <fullClassName> <methodToRun> <argToPass>...");
    }
    else
    {
      // Extract the class name and the method
      String className = args[0];
      String methodName = args[1];
      System.out.println("Class to reflect: " + className);
      System.out.println("Method to call: " + methodName);
      // Extract the arguments to pass and construct a new args array
      String[] argsToPass = new String[args.length - 2];
      for (int argIn = 2, argOut = 0; argIn < args.length; argIn++, argOut++)
      {
        argsToPass[argOut] = args[argIn];
      }
      System.out.println("Args to pass: ");
      for (Object arg : argsToPass)
      {
        System.out.println(arg);
      }
      
      // Do the actual reflection work
      try
      {
        reflectTheClass(className, methodName, argsToPass);
      }
      catch (ClassNotFoundException cnfe)
      {
        cnfe.printStackTrace();
      }
      catch (IllegalArgumentException iae)
      {
        iae.printStackTrace();
      }
    }
  }
  
  /**
   * Does the actual reflection work
   */
  public static void reflectTheClass(
      String className, String methodName, String[] argsToPass)
      throws ClassNotFoundException
  {
    // Now, load in the class to be reflected
    Class theClass = Class.forName(className);
    
    System.out.println("Class loaded; obtaining methods:");
    Method[] methods = theClass.getMethods();
    boolean methodFound = false;
    for (Method method : methods)
    {
      String currentMethodName = method.getName();
      System.out.println(currentMethodName);
      if (currentMethodName.equals(methodName))
      {
        // We're making the simplified assumption that we have
        // no overloaded methods of this name, so we just choose
        // the first one we see.
        methodFound = true;
        System.out.println("Found the specified method");
        // So call it...
        callTheMethod(theClass, method, argsToPass);
        
        // No need to search through any other methods.
        return;
      }
    }
    if (!methodFound)
    {
      throw new IllegalArgumentException(
          "Method '" + methodName + "' not found!");
    }
  }
  
  /**
   * Calls the method from the specified class.
   * (Makes the simplifying assumption that the method takes
   *  an array of arguments that matches what we have supplied.)
   */
  private static void callTheMethod(
      Class theClass, Method theMethod, String[] argsToPass)
  {
    int modifiers = theMethod.getModifiers();
    try
    {
      if (Modifier.isStatic(modifiers))
      {
        // The method is static, so we can just call it
        // (Note that we're assuming that this method has
        // a signature that matches (String[] args) )
        System.out.println("Calling static method '" + theMethod.getName() +
            "' in class '" + theClass.getCanonicalName() + "' ...");
        System.out.println(SEPARATOR);
        
        // Note the first parameter (the instance to use) is ignored 
        // for a static method, so we just supply a null.
        // We also assume that the signature for the method is
        // (String[]) -- for example, a main method.
        theMethod.invoke(null, new Object[] {argsToPass});
      }
      else
      {
        // The method is not static (it's an instance method), 
        // so we have to first create an instance of the class 
        // before we can call the method.
        
        // First let's figure out what we have to supply 
        // for arguments.
        System.out.println("Determining method parameter types.");
        Class[] parameterTypes = theMethod.getParameterTypes();
        
        // And based on the parameter types, construct an Object array
        // to supply the matching values.
        Object[] params = new Object[parameterTypes.length];
        System.out.println("Total of " + parameterTypes.length + " Parameter types:");
        for (int param= 0; param < params.length; param++)
        {
          Class paramType = parameterTypes[param];
          System.out.println("[" + param + "] " + paramType);
          
          // Extract the value from the argsToPass array, converting as appropriate:
          // Simplification:  Only handle int types
          
          // Is it an int?
          if (paramType == int.class)
          {
            params[param] = Integer.parseInt(argsToPass[param]); // autobox
          }
          else
          {
            // Do the appropriate conversion for other types
            // (left as an exercise for the reader...)
          }
        }
        
        // Now, create the instance of the class
        System.out.println("Creating instance of class '" +
            theClass.getCanonicalName() +
            "' using default (no-arg) constructor...");
        Object instance = theClass.newInstance();
        
        // Finally, invoke the method on the instance
        // passing in the parameters.
        System.out.println("Calling instance method '" + theMethod.getName() +
            "' in class '" + theClass.getCanonicalName() + "' ...");
        System.out.println(SEPARATOR);
        
        theMethod.invoke(instance, params);
      }
      
      System.out.println(SEPARATOR);
      System.out.println("... Call completed.");
    }
    catch (IllegalArgumentException ex)
    {
      ex.printStackTrace();
    }
    catch (IllegalAccessException ex)
    {
      ex.printStackTrace();
    }
    catch (InvocationTargetException ex)
    {
      ex.printStackTrace();
    }
    catch (InstantiationException ex)
    {
      ex.printStackTrace();
    }
  }
  
  //// Private data ////
  private static final String SEPARATOR =
      "-------------------------------------------------------------------";
}

Note that there is no reference to the 'reflectee' class from within the 'reflector' class.  The idea is to make it possible for the 'reflector' class to be able to perform reflection on any class that might be within that JVM's class path.

Invoking a static method

If we run the MyReflector class with the following parameters:

reflectee.ReflectMe main 50

the program outputs the following:

Class to reflect: reflectee.ReflectMe
Method to call: main
Args to pass: 
50
Class loaded; obtaining methods:
main
Found the specified method
Calling static method 'main' in class 'reflectee.ReflectMe' ...
-------------------------------------------------------------------
Generating random integer < 50
Random value = 7
-------------------------------------------------------------------
... Call completed.

In other words, it loaded in the reflectee.ReflectMe class, and then invoked that class's main method, passing in a single argument (50).

Invoking an instance method

Here, we run the MyReflector class with the following parameters:

reflectee.ReflectMe setRandomValue 42

As a result, the program outputs the following:

Class to reflect: reflectee.ReflectMe
Method to call: setRandomValue
Args to pass: 
42
Class loaded; obtaining methods:
main
getRandomValue
setRandomValue
Found the specified method
Determining method parameter types.
Total of 1 Parameter types:
[0] int
Creating instance of class 'reflectee.ReflectMe' using default (no-arg) constructor...
Calling instance method 'setRandomValue' in class 'reflectee.ReflectMe' ...
-------------------------------------------------------------------
Setting value to 42
-------------------------------------------------------------------
... Call completed.

In other words, it loaded in the reflectee.ReflectMe class, created an instance thereof, and then invoked that class's setRandomValue method, passing in a single argument of type int (42).

 
The page was last updated February 19, 2008