Reflection in Action Blog


    Have you ever wondered how an IDE lists all your class details, including the private fields and methods? Or how IDEs are also able to list the classes (together with their details) archived within JAR files that include no source?

    These are examples of reflection.

    Together with listing the contents of an arbitrary class, this article will illustrate how reflection can be used to leverage programming and push it to a higher level of abstraction. We will start from very basic examples and move forth by applying reflection within a simple application.

    What Is Reflection?

    Reflection is a mechanism that enables dynamic discovery and binding of classes, methods, fields, and all the other elements the language is made of. Reflection can do more than just simply list classes, fields, and methods. Through reflection, we can actually create instances, invoke methods, and access fields if need be.

    Most programmers have used dynamic class loading when loading their JDBC drivers, using something similar to the following code fragment, where an instance of the MySQL JDBC driver is being dynamically loaded:


    Why and When Should Reflection Be Used?

    Reflection provides a higher level of abstraction. In other words, reflection allows us to examine the object at hand and act accordingly during runtime. For example, imagine you have to perform the same task, such as searching for an instance, on more than one kind of object. You can either write some code for every different kind of object, or you can use reflection. As you may already have realized, reflection can minimize maintenance as the same code, since by using reflection, your instance-searching code will work with other classes. We will come to this example later on. I have included it here just to show you how reflection can be used to our advantage.

    Dynamic Discovery

    Let's start by discovering a class's contents and listing its constructors, fields and methods. This is not that useful, but it is essential to grasp the Reflection API and its potential.

    Create the Product class illustrated below. All our examples are saved under the same package, calledria.

    package ria; public class Product { private String description; private long id; private String name; private double price; //Getters and setters are omitted for shortness } 

    With the Product class ready, we can move on and create the second class, called ReflectionUtil, which will list the first class's (Product) details. As you may have anticipated, this class will include utility methods that will perform all the reflection functionality required within the application. For the time being, this class will only include one method, describeInstance(Object), with one parameter of the type Object.

    The code for the ReflectionUtil class is illustrated in the following listing.

    package ria; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; public class ReflectionUtil { public static void describeInstance(Object object) { Class<?> clazz = object.getClass(); Constructor<?>[] constructors = clazz.getDeclaredConstructors(); Field[] fields = clazz.getDeclaredFields(); Method[] methods = clazz.getDeclaredMethods(); System.out.println("Description for class: " + clazz.getName()); System.out.println(); System.out.println("Summary"); System.out.println("-----------------------------------------"); System.out.println("Constructors: " + (constructors.length)); System.out.println("Fields: " + (fields.length)); System.out.println("Methods: " + (methods.length)); System.out.println(); System.out.println(); System.out.println("Details"); System.out.println("-----------------------------------------"); if (constructors.length > 0) { System.out.println(); System.out.println("Constructors:"); for (Constructor<?> constructor : constructors) { System.out.println(constructor); } } if (fields.length > 0) { System.out.println(); System.out.println("Fields:"); for (Field field : fields) { System.out.println(field); } } if (methods.length > 0) { System.out.println(); System.out.println("Methods:"); for (Method method : methods) { System.out.println(method); } } } } 

    Java includes a set of reflection-related classes packaged under the Reflection API. The classes Constructor,Field, and Method are some of the classes belonging to this package. Like the well known Classclass, these are used by Java to represent the programs we write as objects. In order to describe an object, we need to know what it is made of. Where do we start? We start from the class, as it contains all of our code.

    Class<?> clazz = object.getClass(); 

    Notice the generic declaration Class<?>. Generics, in a nutshell, provide type-safe operations by ensuring that a given instance is of the specified type. Our method (describeInstance(Object)) is not bound to a specific type and is designed to work with any given object. Thus the unbounded wildcard, <?>, is used instead.

    The Class class has a number of methods. We'll focus on some that are relevant to us. These methods are illustrated in the following code fragment.

    Constructor<?>[] constructors = clazz.getDeclaredConstructors(); Field[] fields = clazz.getDeclaredFields(); Method[] methods = clazz.getDeclaredMethods(); 

    The above Class methods return arrays of constructors, fields, and the methods that this object is made from.

    Note that the Class class includes two sets of getter methods: one set includes the declared word in their names, and the other set does not. The difference is thatgetDeclaredMethods() will return all methods that belong to the class, while getMethods() returns only the public ones. It's also important to understand that only methods declared within the class are returned. Inherited methods are not retrieved.

    It's important to understand that theReflectionUtil class doesn't have a reference to theProduct class. We need another class that creates an instance of the product details class and prints its details.

    package ria; public class Main { public static void main(String[] args) throws Exception { Product product = new Product(); product.setId(300); product.setName("My Java Product Name"); product.setDescription("My Java Product description..."); product.setPrice(10.10); ReflectionUtil.describeInstance(product); } } 

    The above class should produce the following output (or something similar):

    Description for class: ria.Product Summary ----------------------------------------- Constructors: 1 Fields: 4 Methods: 8 Details ----------------------------------------- Constructors: public ria.Product() Fields: private java.lang.String ria.Product.description private long private java.lang.String private double ria.Product.price Methods: public java.lang.String ria.Product.getName() public long ria.Product.getId() public void ria.Product.setName(java.lang.String) public void ria.Product.setId(long) public void ria.Product.setDescription(java.lang.String) public void ria.Product.setPrice(double) public java.lang.String ria.Product.getDescription() public double ria.Product.getPrice() 

    For this method to be more useful, it should also print the values of the instance being described together with the class details. The Field class includes a method calledget(Object) that returns the value of the field for the given instance.

    For example, let's take our Product class. The class has four instance variables. The retrieved values are dependent on the instance, as different instances may have different values. Thus the instance must be provided to theField in order to return its value as shown below:


    where field is an instance of Fieldand the object is an instance of any Java class.

    Before we hastily start adding any code, we must appreciate the fact that the fields of our class have the privateaccess modifier. An exception is thrown if we invoke theget(Object) method as it is. We need to invoke the method setAccessible(boolean) for theField class and pass true as the parameter before attempting to access the field's value.


    Now that we know all the tricks involved in getting a field's value, we can add the following code at the bottom of thedecribeInstance(Object) method.

    if (fields.length > 0) { System.out.println(); System.out.println(); System.out.println("Fields' values"); System.out.println("-----------------------------------------"); for (Field field : fields) { System.out.print(field.getName()); System.out.print(" = "); try { field.setAccessible(true); System.out.println(field.get(object)); } catch (IllegalAccessException e) { System.out.println("(Exception Thrown: " + e + ")"); } } } 

    To show you its effectiveness, I'm going to create an instance of the java.awt.Rectangle class and print its details using the describeInstance(Object) method.

    Rectangle rectangle = new Rectangle(1, 2, 100, 200); ReflectionUtil.describeInstance(rectangle); 

    The above code fragment should produce something similar to the following. Note that some of the output is truncated, as it's too long to display.

    Description for class: java.awt.Rectangle Summary ----------------------------------------- Constructors: 7 Fields: 5 Methods: 39 Details ----------------------------------------- Constructors: public java.awt.Rectangle() public java.awt.Rectangle(java.awt.Rectangle) public java.awt.Rectangle(int,int,int,int) public java.awt.Rectangle(int,int) public java.awt.Rectangle(java.awt.Point,java.awt.Dimension) public java.awt.Rectangle(java.awt.Point) public java.awt.Rectangle(java.awt.Dimension) Fields: public int java.awt.Rectangle.x public int java.awt.Rectangle.y public int java.awt.Rectangle.width public int java.awt.Rectangle.height private static final long java.awt.Rectangle.serialVersionUID Methods: public void java.awt.Rectangle.add(int,int) public void java.awt.Rectangle.add(java.awt.Point) public void java.awt.Rectangle.add(java.awt.Rectangle) public boolean java.awt.Rectangle.equals(java.lang.Object) public java.lang.String java.awt.Rectangle.toString() public boolean java.awt.Rectangle.contains(int,int,int,int) public boolean java.awt.Rectangle.contains(java.awt.Rectangle) public boolean java.awt.Rectangle.contains(int,int) public boolean java.awt.Rectangle.contains(java.awt.Point) public boolean java.awt.Rectangle.isEmpty() public java.awt.Point java.awt.Rectangle.getLocation() public java.awt.Dimension java.awt.Rectangle.getSize() public void java.awt.Rectangle.setSize(java.awt.Dimension) public void java.awt.Rectangle.setSize(int,int) public void java.awt.Rectangle.resize(int,int) private static native void java.awt.Rectangle.initIDs() public void java.awt.Rectangle.grow(int,int) public boolean java.awt.Rectangle.intersects(java.awt.Rectangle) private static int java.awt.Rectangle.clip(double,boolean) public java.awt.geom.Rectangle2D java.awt.Rectangle.createIntersection(java.... public java.awt.geom.Rectangle2D java.awt.Rectangle.createUnion(java.awt.geo... public java.awt.Rectangle java.awt.Rectangle.getBounds() public java.awt.geom.Rectangle2D java.awt.Rectangle.getBounds2D() public double java.awt.Rectangle.getHeight() public double java.awt.Rectangle.getWidth() public double java.awt.Rectangle.getX() public double java.awt.Rectangle.getY() public boolean java.awt.Rectangle.inside(int,int) public java.awt.Rectangle java.awt.Rectangle.intersection(java.awt.Rectangle) public void java.awt.Rectangle.move(int,int) public int java.awt.Rectangle.outcode(double,double) public void java.awt.Rectangle.reshape(int,int,int,int) public void java.awt.Rectangle.setBounds(int,int,int,int) public void java.awt.Rectangle.setBounds(java.awt.Rectangle) public void java.awt.Rectangle.setLocation(java.awt.Point) public void java.awt.Rectangle.setLocation(int,int) public void java.awt.Rectangle.setRect(double,double,double,double) public void java.awt.Rectangle.translate(int,int) public java.awt.Rectangle java.awt.Rectangle.union(java.awt.Rectangle) Fields' values ----------------------------------------- x = 1 y = 2 width = 100 height = 200 serialVersionUID = -4345857070255674764 

    Create a New Instance Using Reflection

    Reflection can also be used to create instances of a new object. There are cases, such as when dynamically loading a JDBC driver as illustrated previously, where an instance of the object needs to be created dynamically. Furthermore, we can use theConstructor class to create new instances, especially for instances that require parameters during their instantiation. The following two overloaded methods can be added to ourReflectionUtil class.

    public static <T> T newInstance(Class<T> clazz) throws IllegalArgumentException, SecurityException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException { return newInstance(clazz, new Class[0], new Object[0]); } public static <T> T newInstance(Class<T> clazz, Class<?>[] paramClazzes, Object[] params) throws IllegalArgumentException, SecurityException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException { return clazz.getConstructor(paramClazzes).newInstance(params); } 

    Note that the newInstance(Object[]) will throw exceptions if the constructor arguments supplied are not adequate. The class being instantiated must contain a constructor with the given signature.

    The first method (newInstance(Class<T>)) can be used to instantiate an object from any class having a default constructor. Alternatively, the second method can be used. By passing the parameter types and their values in the respective parameters, the instantiation will happen through the matching constructor. For example, the Rectangle class can be instantiated using the constructor with four parameters of the typeint, using the following code:

    Object[] params = { 1, 2, 100, 200 }; Class[] paramClazzes = { int.class, int.class, int.class, int.class }; Rectangle rectangle = ReflectionUtil.newInstance( Rectangle.class, paramClazzes, params); System.out.println(rectangle); 

    The above will produce the following output.


    Changing the Fields's Values Through Reflection

    The fields's values can be set through reflection in a fashion similar to how they are read. It is import to set the field's accessibility before trying to set the value, as otherwise an exception is thrown.

    field.setAccessible(true); field.set(object, newValue); 

    We can easily draft a method that can set the value of any object, as shown in the following example.

    public static void setFieldValue(Object object, String fieldName, Object newValue) throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException { Class<?> clazz = object.getClass(); Field field = clazz.getDeclaredField(fieldName); field.setAccessible(true); field.set(object, newValue); } 

    This method has a pitfall, as it only retrieves fields from the given class; inherited fields are not included. This can quickly be fixed using the following method, which looks up the object hierarchy for the required Field.

    public static Field getDeclaredField(Object object, String name) throws NoSuchFieldException { Field field = null; Class<?> clazz = object.getClass(); do { try { field = clazz.getDeclaredField(name); } catch (Exception e) { } } while (field == null & (clazz = clazz.getSuperclass()) != null); if (field == null) { throw new NoSuchFieldException(); } return field; } 

    This method will return the Field with the given name, if found; otherwise it will throw an exception to indicate that this object neither has nor inherits this field. It starts searching from the given class and works its way up the hierarchy until either the Field is found, or no superclass is available.

    Note that all Java classes inherit (directly or transitively) from the Object class. As you may have realized, theObject class does not inherit from itself. Thus theObject class does not have a superclass.

    The method setFieldValue(Object, String, Object)illustrated previously is modified to cater for this situation. The changes are shown in bold below.

    public static void setFieldValue(Object object, String fieldName, Object newValue) throws IllegalArgumentException, IllegalAccessException
    , NoSuchFieldException { 
    Field field = getDeclaredField(object, fieldName); field.setAccessible(true); field.set(object, newValue); } 

    Let's create another class called Book that extends the Product class discussed earlier, and apply what we've learned so far.

    package ria; public class Book extends Product { private String isbn; //Getters and setters are omitted for shortness } 

    Now let's set the book's id using thesetFieldValue(Object, String, Object) method.

    Book book = new Book(); ReflectionUtil.setFieldValue(book, "id", 1234L); System.out.println(book.getId()); 

    The above will produce the following output:1234.

    Invoking Methods Through Reflection

    As you may already have assumed, the invocation of methods is very similar to creating new instances and accessing fields discussed above.

    As far as reflection is concerned, all methods have parameters and return a value. This may sound weird, but it's true. Let's analyze the following method:

    public void doNothing(){ // This method doesn't do anything } 

    This method has a return type, of the type void, and an empty parameter list. It can be invoked through reflection in the following manner.

    Class<?> clazz = object.getClass(); Method method = Clazz.getDeclaredMethod("doNothing"); method.invoke(object, new Object[0]); 

    The invoke method, from the Methodclass, requires two arguments: the instance on which the method will be invoked, and the list of parameters as an array of objects. Note that the method doNothing() has no parameters. Despite that, we still need to specify the arguments as an empty array of objects.

    A method also has a return type; void, in our case. The return value, if any, can be saved as an Objectsomething similar to the following example.

    Object returnValue = method.invoke(object, new Object[0]); 

    In this case, the return value is null as this method does not return anything. Note that methods can return anull on purpose and this may be a little confusing.

    Before we finalize this section, it's important to understand that a method can be inherited in the same way that fields are. We can have another utility method to retrieve the method within the hierarchy rather than just from the class at hand.

    public static Method getDeclaredMethod(Object object, String name) throws NoSuchMethodException { Method method = null; Class<?> clazz = object.getClass(); do { try { method = clazz.getDeclaredMethod(name); } catch (Exception e) { } } while (method == null & (clazz = clazz.getSuperclass()) != null); if (method == null) { throw new NoSuchMethodException(); } return method; } 

    Finally, the generic invoke method is listed below. Note again the methods may be private and thus it's ideal to set their accessibility before invoking them.

    public static Object invokeMethod(Object object, String methodName, Object[] arguments) throws NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException { Method method = getDeclaredMethod(object, methodName); method.setAccessible(true); return method.invoke(object, arguments); } 

    Apart from executing private methods, invocation of methods through reflection can be useful to expose functionality and easily change the execution flow during runtime.

    Reflection Within an Application

    Until now, we have only created utility methods and tried out simple examples. Real-life programming requires more than that. Imagine that we need to search through our objects and determine whether a given object matches some criteria or not. The first option is to write an interface and implement it in every object that returns true if this instance matches the criteria, false otherwise. Unfortunately, this approach requires us to implement a method within everyclass we have. New classes will have to implement this interface and provide a body for its abstract method. Alternatively, we can use reflection to retrieve the object's fields and check whether their values meet the criteria.

    Let us first create another method that returns the object's fields. Remember that there's no built-in method that returns all the fields including the inherited ones. Thus we need to retrieve them ourselves by extracting them set by set until we reach the top of the hierarchy. This method can be added to theReflectionUtil class.

    public static List <Field> getDeclaredFields(Class clazz) { List<Field> fields = new ArrayList<Field>(); do { try { fields.addAll(Arrays.asList(clazz.getDeclaredFields())); } catch (Exception e) { } } while ((clazz = clazz.getSuperclass()) != null); return fields; } 

    Now we only need to match their string values with the given criteria, as shown in the following code fragment. TheString method valueOf(Object) is used to convert the fields's values into strings without returningnull or throwing any exceptions. Note that this may not always work for complex data types.

    public static boolean search(Object object, String criteria) throws IllegalArgumentException, IllegalAccessException { List <Field> fields = ReflectionUtil.getDeclaredFields(object.getClass()); for (Field field : fields) { field.setAccessible(true); if (String.valueOf(field.get(object)).equalsIgnoreCase(criteria)) { return true; } } return false; } 

    Let's create a new class called Address and try this out. The code for this class is shown below.

    package ria; public class Address { private String country; private String county; private String street; private String town; private String unit; //Getters and setters are omitted for shortness } 

    Now let's create an instance of both the Book andAddress classes and apply our search method.

    Book book = new Book(); book.setId(200); book.setName("Reflection in Action"); book.setIsbn("123456789-X"); book.setDescription("An article about reflection"); Address address = new Address(); address.setUnit("1"); address.setStreet("Republic Street"); address.setTown("Valletta"); address.setCountry("Malta"); System.out.println("Book match? " + search(book, "Valletta")); System.out.println("Address match? " + search(address, "Valletta")); 

    The first match (the one against the book instance) will returnfalse, while the address instance will returntrue. The search method can be applied against any object without having to add or implement anything.

    Drawbacks of Reflection

    Until now we've only talked about how good reflection is and how it can make life easier. Unfortunately, everything comes with a price. Reflection is very powerful and provides a great deal of flexibility, but we should not start programming everything using reflection. If possible, you may want avoid using reflection in some cases as it introduces the following drawbacks: performance overhead, security restrictions, and exposure of hidden members.

    Sometimes logic is preserved through access modifiers. The following code fragment is a clear example:

    public class Student { private String name; public Student(String name){ = name; } } 

    The student's name can only be changed through the constructor, when the object is initialized. Reflection allows you to set the student's name to any String even after the object is initialized. As you can see, this disrupts the business logic and may cause the program to behave in an unpredictable way.

    The Java compiler, like most other compilers, tries to optimize the code as much as possible. This is not possible with reflection as the types are resolved at runtime, while the compiler works at compile time. Furthermore, the type must be resolved at a later stage, which is at runtime.


    Reflection can be used to apply the same logic--search, for example--against different objects without having to implement a new version of the code for every new type. This also centralizes the logic in one place. It unfortunately has drawbacks in that it can increase the code complexity. Performance is another side effect of reflection as optimizations cannot be performed on such code.