EP08 – Java Reflection – Writing Generic Java Code

If you’ve ever used the JavaScript language before, you might be familiar with the eval() function.

If you’ve never used JavaScript before, then no worries, I’ll have an in-depth explanation as to what’s going on.

For you JavaScript coders out there, the eval() function is used so that you can write any strings you like inside of the function, and the JavaScript engine will interpret it and run it like it was native JS code.

This “execution of code written out as Strings” concept is very similar to what reflection in Java accomplishes.

Reflection in Java is a way to call the methods of objects without needing the actual reference to those objects.

Another way to say it is, you can programmatically execute methods with reflection in Java.

Getting Started with Java Reflection

So, one of the keys to working with reflection in Java is to make use of the Method class.

The Method class gives us access to some cool stuff… Namely the ability to “invoke” methods that you want to have invoked (programmatically).

Let’s assume you’ve got a standard Java class that has some getter and setter methods like so:

public class User 
{
  private Long id;
  private String email;
  private String password;

  public Long getId()
  {
    return id;
  }

  public void setId(Long id)
  {
    this.id = id;
  }

  public String getPassword()
  {
    return password;
  }

  public void setPassword(String password)
  {
    this.password = password;
  }

  public String getEmail()
  {
    return email;
  }

  public void setEmail(String email)
  {
    this.email = email;
  }
}

The User above is a super common Java bean that represents some user.

You’ve seen what it looks like to “invoke” any of these methods. For example, if we wanted to invoke the getter method for a User‘s email, it would be:

// Let's assume we can load a user from the database by ID like so:
User aUser = userRepository.findOne(1L);

// now we invoke the getEmail() method to get the email address of user with ID 1.
String userEmail = aUser.getEmail();

Nothing fancy going on here (assuming you know what a repository is, if you don’t I’d recommend reading about it here)

So now let’s introduce Java reflection.

Here’s that same code, only now we’ll invoke the getter method using reflection:

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

User aUser = userRepository.findOne(1L);

try
{
  Method method = aUser.getClass().getMethod("getEmail");
  
  String userEmail = (String) method.invoke(aUser);
} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e)
{
  // If your code makes it in here, you're likely having an issue with one of the following:
  //  1. Your method name is incorrect / doesn't exist on the User class
  //  2. The method exists, but when Java tried to invoke it, you didn't pass the right object to invoke the method on
  //  3. The method exists and you passed the right Java object, but you didn't give it the correct method signature (i.e. you didn't pass in the right types for the parameters.
  e.printStackTrace();
}

Naturally it takes more code to make reflection do its thing, namely in the number of exceptions that need handling.

But the “business-end” of the code really comes down to two things:

  1. Assigning a Method variable with the appropriate method you wish to invoke
  2. Invoking the method

The first step is accomplished by first getting the appropriate class with which you’d like to work: aUser.getClass(). Then once we have the class we’d like to work with, we can locate the method we’d like to invoke via the getMethod() method.

Very meta.

The most important thing to note here is that the process of “getting a method” via the getMethod() method takes a String as an argument.

This means that you can pass in a String variable to this method… This means that the process of “getting” a method and invoking it can be completely dynamic and can change at run-time.

This is the whole reason why Java reflection exists! The ability to programmatically invoke methods.

Using Reflection to Invoke Methods with Parameters

Okay, so we’ve seen how to invoke a method that takes no parameters (i.e. a “getter” method) Now let’s take a look at how to invoke a method that takes an argument (i.e. a “setter” method)

Note: just in case you’re thinking that reflection is only get “getter” and “setter” methods, it is not, you can use reflection to invoke almost any methods you’d like. I say “almost” any methods because I’m not exactly sure if it can be used to invoke ANY method you want, so I’m just covering my own butt 🙂

Okay, having said that, let’s invoke the setEmail() method with Java reflection:

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

User aUser = userRepository.findOne(1L);

try
{
  Method method = aUser.getClass().getMethod("setEmail", String.class);

  method.invoke(aUser, "trevor@craftycodr.com");
} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException
    | InvocationTargetException e)
{
  e.printStackTrace();
}

What our code above will do is the equivalent of writing aUser.setEmail("trevor@craftycodr.com").

The difference that you’ll notice between the first Java reflection example and the second is that we have to add parameters to our getMethod() and method.invoke() methods.

We need to tell Java what the method signature is for the method we’d like to invoke. The reason we need to do this is because we can have methods with the same names, but different arguments in their method signatures. So just giving the name wouldn’t be enough information for Java to locate the specific method you’d like to invoke.

And secondly, you need to actually pass the value(s) of the arguments for the method to use when invoked.

Iterating Through the Methods of a Class

Now, there may come a time when you don’t want to pass the exact method name and method signature of the method you’d like to programmatically invoke.

One real-world example of this scenario is when saving values via an AJAX call.

If we have a form that needs to be filled out on a webpage, and the values will be sent to a database for storage as soon as the form fields are filled out, then reflection plays an important role.

Here’s a snippet of code that I’ve used before to save both String and Double values from form fields.


// passing in, for example: emailAddress (as the fieldName)
//  we need to capitalize the first letter to properly invoke the setter method (i.e. emailAddress becomes EmailAddress)
fieldName = StringUtils.capitalize(fieldName);

// get all the methods for a given class. Let's assume we've passed in User.class as the clazz variable
Method[] methods = clazz.getMethods();
Method method = null; 

// since we grabbed all the methods from the User class (for example), we can iterate through them all
for (Method aMethod : methods)
{
  // find any method that equals the one exact one we're searching for (i.e. "setEmailAddress")
  if (aMethod.getName().equals("set" + fieldName))
  {
    method = aMethod;
    // if this setter method is expecting a String, then we set the value that we got from the webpage
    if (method.getParameterTypes()[0].getName().indexOf("String") > -1)
    {
      // we know that this setter method takes a String
      method.invoke(obj, fieldValue);
    }
    // if this setter method is expecting a Double, then we convert the value from a String to a Double and set it
    else if (method.getParameterTypes()[0].getName().indexOf("Double") > -1)
    {
      // If we're parsing a monetary value, then strip out any currency characters in the String before converting to a Double
      fieldValue = fieldValue.replace("$", "");
      
      // we know that this setter method takes a Double
      method.invoke(obj, Double.valueOf(fieldValue));
    }
    break;
  }
}

// save the object that was modified by the Java reflection code... in this case, we can assume that the "obj" variable is "aUser".
repo.save(obj);

This is some lovely and generic code that allows me to invoke the setter methods of ANY object I wish, and it will dynamically convert the values that I wish to set into the methods (given that it’s either a String or a Double). Of course, I can also program it to convert from a String to any other data types, I just need to add them into the if structure.