Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Java Generic Code - Reflection, the Easy Way

0.00/5 (No votes)
7 Jun 2010 1  
Make Java's Reflection easier with this utility class.

Introduction

During your career as a Software Designer/Programmer you will probably encounter the need to use Objects at run-time without knowing much about them at design-time. Java enables this with Reflection.  

Java Generic Code - Dealing With Reflection, the Easy Way

If you have ever done any work with JDBC then the following code would seem familiar:

public Connection getConnection(String driverClass, String dbUrl, String userName, 
                                String passWord) {
    Connection connection = null;
    try {
        if (Class.forName(driverClass) != null) {
            connection = DriverManager.getConnection(dbURL, userName, passWord);
            if (connection != null) {
                connection.setAutoCommit(false);
            }
        }
    } catch (Exception ex) {
        ex.printStackTrace();
    }
    return connection;
}

If you ever written similar code, you've used Reflection.

What is it anyway?

Reflection is a set of API's that Java employs to solve a variety of problems. For instance, using an IDE to design a GUI involves playing with a lot of controls, adding them to a frame and tweaking their properties. Your IDE (if written in Java) is using Reflection to load the classes, determine what properties they have, allowing you to modify those properties and invoke the appropriate methods in the objects to change the properties to the values you've chosen.

What can we do with it?

As you know, runtime Objects must be loaded and have fields and methods. Therefore Reflection concentrates on three things:

  1. Letting you load classes on the fly when you only know the name of the class during run-time.
  2. Letting you access the fields of an object without actually knowing their names or types beforehand.
  3. Letting you invoke methods in these anonymous objects.

Why is it hard?

Finding your way around Java's Reflection API can be a challenge, especially when you're pressed for time. For that reason, I have collected most of my knowledge about Reflection into an easy to use utility class. I will present this class in short by using a demo program.

The Demo

The demo program is very simple: I will attempt to load a class by its fully-qualified name (i.e. package name + class name), and then manipulate it by invoking a method known to me by name only.

The class structure for the code in the demo is as follows:

  • dev.easyref.tester: DemoApplication - The demo's main class.
  • dev.easyref.data : Employee - A simple data class which I load in run-time.
  • dev.easyref.util: Arguments - The utility class used to perform all the Reflection work.

The following Employee class simply contains information:

public class Employee {
  // These are the data-members, notice that we can never access them externally..
  private int age;
  private float salary;
  private String firstName;
  private String lastName;

  public Employee(String firstName, String lastName, int age, float salary) {
    this.age = age;
    this.salary = salary;
    this.firstName = firstName;
    this.lastName = lastName;
  }

  public void updateSalary(float increase) {
    salary += increase;
  }

  public String toString() {
    return "<Employee Name: [" + firstName + ", " + lastName + "], Age: [" + age + "], "
           "Salary: [" + salary + "]>";
  }
}

The demo code manipulates the Employee class as follows:

 1: import dev.easyref.util.*;

 2: public class DemoApplication {
 3:   public static void main(String[] args) {
 4:   // Create an Arguments object..
 5:     Arguments xArgs = new Arguments();
 6:     // Fill the Arguments object with data..
 7:     xArgs.addElement("Doron");
 8:     xArgs.addElement("Barak");
 9:     xArgs.addElement(36);
10:     xArgs.addElement(3000.0f);
11:     // Create an instance of an Employee class based on the data..
12:     Object o = xArgs.getInstance("dev.easyref.data.Employee");
13:     // Show the object that we received..
14:     System.out.println("Created instance >>   " + o);
15:     // Create a new Arguments object, collecting the data in the object..
16:     xArgs = new Arguments(o);
17:     // Display the collected data..
18:     System.out.println("Instace data >>       " + xArgs);
19:     // Change the first stored value to 1000..
20:     xArgs.setElementAt(1000.0f, 1);
21:     // Order the Arguments object to not print Excpetion stacks..
22:     xArgs.hideExceptions();
23:     // Invoke the updateSalary() method of the Employee instance..
24:     xArgs.runMethod(o, "updateSalary");
25:     // Check to see if we had an Excpetion..
26:     if (xArgs.hadMethodError()) {
27:       // Remove unwanted values from the Arguments object..
28:       xArgs.removeElementAt(0);
29:       xArgs.removeElementAt(1);
30:       xArgs.removeElementAt(1);
31:       // Now, we try to invoke updateSalary() again..
32:       xArgs.runMethod(o, "updateSalary");
33:     }
34:     // Display object after Salary raise..
35:     System.out.println("After Salary Raise >> " + o);
36:   }
37: }

Lines 5-10:
Starting at lines 5-10, an Arguments object is created and data is added to it. The data is added in the order it would appear if the constructor of the Employee class would have been used. My Arguments object extends Java's Vector object for ease of use in manipulating its data elements.

Lines 12-14:
Here the Arguments object is used to get an instance of the dev.easyref.data.Employee class and then display the result. The getInstance() method of the Arguments object does all the work of calling Class.forName() and negotiating with properly invoking the constructor of the requested Class.

Lines 16-18:
The Arguments object is now used to collect all the data present in the Employee instance and then the Arguments object is displayed. Please note that the data collected into the Arguments object matches in its element order and type, the data members declared in the Employee class.

Lines 20-24:
A float value of 1,000 is set into the first slot of the Arguments object using the setElementAt() method inherited from the Vector class. Next the Arguments object is ordered to hide all run-time exceptions and attempt to invoke the updateSalary() method of the Employee instance. As you may have guessed, the reason I hide the exceptions is because invoking the method at this stage does result in a NoSuchMethodException as the data currently contained in the Arguments object does not match the method-signature of the updateSalary() method.

Lines 26-35:
An Arguments object can be queried to see if the last method-invocation resulted in an error. Since we know that it did, we now remove the unwanted data and try to re-invoke the updateSalary() method, now with the proper value. To prove that the salary has been properly raised, I display the Employee instance again.

The output of the demo application should look like this:
Created instance >> <Employee Name: [Doron, Barak], Age: [36], Salary: [3000.0]>
Instace data >> [36, 3000.0, Doron, Barak]
ERROR: Method not found for class [dev.easyref.data.Employee] {
updateSalary(int p0, float p1, String p2, String p3);
}
After Salary Raise >> <Employee Name: [Doron, Barak], Age: [36], Salary: [4000.0]>

You probably noticed that even though the Arguments object showed no exception, it did report the unfortunate result of the method invocation with an error message sent to the System.err stream.

In Conclusion

Download the code and have fun with it. Java's Reflection is a very important tool without which a lot of Java's features simply would not exist. Without Reflection you would not be able to use a sophisticated IDE to design a GUI. You would also not be able to use neither Serialization nor RMI.

You can use the Arguments class itself in your applications, I only wish I had the time to properly document it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here