Core Java

Method Handles in Java

In this example, we will discuss in detail about Method Handles in Java, a feature introduced in Java 1.7. We will talk about the Java Reflection API and its performance issues, method handles, why were they introduced, and how to create and use them.

1. The Java Reflection API

The old school Java Reflection API (introduced in Java 1.1) is a powerful tool for programmatic access to extract and discover the information about constructors, methods, and fields of the classes loaded in JVM.

It can also be used to create an instance of a class, change the values of member variables, and invoke instance methods irrespective of their access specifiers.

The classes and interfaces for Reflection are available in the java.lang.reflect package. For a detailed course on reflection click here.

1.1. Performance Issues With The Reflection API

Whenever a piece of code uses the Java Reflection API, there are certain security checks that look for the Security Manager, and if one found, checks are done to verify if the caller has the right to access reflection or not. Further security checks like Reflection.ensureMemberAccess are carried out to ensure that access to a member is granted.

All these checks are conducted every time a call is made using reflection. Even if the same caller calls the same reflection method, again and again, these checks are performed. They have been found to be costly with a noticeable effect on the performance of the application.

2. What are Method Handles in Java?

As stated in the Java API documentation of MethodHandle:

A method handle is a typed, directly executable reference to an underlying method, constructor, field, or similar low-level operation, with optional transformations of arguments or return values. These transformations are quite general and include such patterns as conversion, insertion, deletion, and substitution.

In other words, a method handle is a lightweight reference to a method, constructor, or even a field that can be executed to invoke the method or to do an operation on a field to read or write its value. Method handles are immutable and have no visible state but the underlying methods bound to by the handle do exhibit a state.

This example will show how a MethodHandle is a much more modern alternative to the traditional old school Reflection API and how it overcomes its performance issues.

2.1. How Method Handles Improve Performance

From a performance point of view, MethodHandles API can be faster than the Reflection API. Let’s see how.

  • The entry point for a Method Handle is the Lookup object. The Lookup object encapsulates the security information and provides methods to creates method handles for constructors, fields, and methods of a class.
  • Method handles perform access checks at creation time and not at execution time. Hence, the access restrictions must be specified when a method handle is created.

3. Using The Method Handles API

The following steps should be followed to create and use Method handles:

  1. Creating the entry point, the Lookup object.
  2. Creating the MethodType required by the Method handle. MethodType represents the arguments and the return type of the method to be looked up.
  3. Creating the MethodHandle, and finally
  4. Invoking it.

Let’s see some examples of method handles on methods, fields, and constructors of a class and some code in action.

3.1 Creating the Lookup

The MethodHandles class provides multiple static methods to create the lookup object. They are:

  • publicLookup() – It creates and returns a lookup with minimal trust, which can be used to create method handles for public members of public classes only.
  • lookup() – Invoking this method returns a lookup that can be used to create method handles for any member that the caller has access to. Care should be taken so that untrusted code doesn’t get access to this lookup object.
  • privateLookupIn​(Class < ? > targetClass, MethodHandles.Lookup lookup) – This method returns a lookup with full capabilities, even accessing the private and protected members of a class.

Let’s see how to create a lookup and a privateLookup object.

Create lookup

private static Lookup lookup = MethodHandles.lookup();
private static Lookup privateLookup = MethodHandles.privateLookupIn(Country.class, lookup);

Also, below is the class Country that will be tested using method handles. It has a mix of private and public fields, an empty constructor, a parameterized constructor and a static method which we will be invoking using method handles.

Country.java

package org.adee.methodhandles.model;

public class Country {

	public String name;
	private int population;

	public Country(String name, int population) {
		this.name = name;
		this.population = population;
	}

	public Country() {
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getPopulation() {
		return population;
	}

	public void setPopulation(int population) {
		this.population = population;
	}

	public static String[] getDetails() {
		return new String[] { "package : org.adee.methodhandles.model", "class : COUNTRY" };
	}

	@Override
	public String toString() {
		return "Country [name=" + name + ", population=" + population + "]";
	}
}

3.2. Creating the MethodType

The Lookup object needs the signature and the return type of the method for which we intend to create a method handle. This is provided by an object of a class MethodType which represents the return type and an array of parameter types of the method we intend to lookup.

The structure of a MethodType is a return type along with any number of parameter types. Just like the MethodHandle, instances of a MethodType are also immutable. The following are some examples to create MethodType objects.

Creating Method Types

		// for a method that returns void and accepts a String argument 
		MethodType setter = MethodType.methodType(void.class, String.class);

		// for a method that returns a String and accepts no arguments. 
		MethodType getter = MethodType.methodType(String.class);

		// method type for a no-args constructor 
		MethodType noArgsConstructor = MethodType.methodType(void.class);

		// method type for a parametrized constructor 
		MethodType constructor = MethodType.methodType(void.class, String.class, int.class);

The first argument in the above examples represents the return type of the method to be looked up and the subsequent arguments represent the method parameters. A return type of void is represented by a void.class and primitive types are represented as int.class, float.class etc.

3.3 Finding The Correct Method Handle

In order to create the MethodHandle, you need to find the appropriate method in the Lookup class depending on what you are trying to lookup (a constructor, a method, or a field).

The Lookup factory provides a set of methods that help us to create the correct method handle. Let’s explore the important ones below.

3.3.1 Method Handle For Public Methods

Method Handles For Public Methods

	private static void invokeSetCountry(Country country) {
		// for a method that returns void and accepts a String argument.
		MethodType setter = MethodType.methodType(void.class, String.class);
		try {
			MethodHandle handle = publicLookup.findVirtual(Country.class, "setName", setter);
			handle.invoke(country, "Greece");
		} catch (Throwable e) {
			e.printStackTrace();
		}
		System.out.println(country);
	}

The above code creates a MethodType for the method “setName()” that returns void and accepts a String and uses the “findVirtual” method from the Lookup class to create the method handle.

Finally, the invoke method of the MethodHandle is called by passing an instance of the class Country and the value to be passed to the setName method.

3.3.2 Method Handle For Public Fields

Method Handles For Public Fields

	private static String FIELD_NAME = "name";
	private static void invokeWriteActionPublicField(Country country) {
		MethodHandle nameFieldHandle = null;
		try {
			// A method handle giving write access to a non-static field , name in this case
			nameFieldHandle = lookup.findSetter(Country.class, FIELD_NAME, String.class);
		} catch (NoSuchFieldException | IllegalAccessException e) {
			e.printStackTrace();
		}
		try {
			// first argument is the instance containing the field and the second arg
			// is the value to be stored
			nameFieldHandle.invoke(country, "United Kingdom");
		} catch (Throwable e) {
			e.printStackTrace();
		}
	}

The above code creates a method handle for the public field “name” of type String, defined in the class Country. The method findSetter in the Lookup class creates a method handle giving write access to a non-static field.

Since it is a handle for a Field and not a Method, the findSetter method does not require a MethodType argument. The invocation of this method handle is quite straightforward as seen above.

3.3.3. Method Handle For Constructors

Method Handles For Constructors

	
// method type for a no-args constructor
MethodType noArgsConstructor = MethodType.methodType(void.class);
MethodHandle noArgConstructorHandle = lookup.findConstructor(Country.class, noArgsConstructor);

// method type for a parametrized constructor
MethodType constructor = MethodType.methodType(void.class, String.class, int.class);
MethodHandle constructorHandle = lookup.findConstructor(Country.class, constructor);

// invoke a parametrized constructor
constructorHandle.invokeWithArguments("China", 1392700000)

// invoke a no-args constructor
noArgConstructorHandle.invoke()

The findConstructor method of the Lookup class is used to discover and lookup constructors. The above code snippet shows creating MethodType and MethodHandle for constructors and the way they are invoked.

The no-args constructor’s MethodType is created by passing a single argument void.class and the parametrized constructor’s MethodType requires two additional parameters, the arguments of the constructor i.e. String.class and int.class.

The no-arguments constructor is invoked by calling the invoke method on the method handle without passing any arguments. Similarly, the method Handle class provides an “invokeWithArguments” method that can be used to invoke the parameterized constructor by passing the arguments “China” and 1392700000 as in the above example.

3.3.4 Method Handle For Private Fields

Method Handles For Private Fields

	private static String FIELD_POPULATION = "population";

			privateLookup = MethodHandles.privateLookupIn(Country.class, lookup);

			MethodHandle getter = privateLookup.findGetter(Country.class, FIELD_POPULATION, int.class);
			

To access a private field, first, we need to create a private lookup that has full access capabilities. This lookup can be used then to lookup a method handle for the private method getPopulation() that returns an int.

3.3.5. Method Handle For Static Methods

Method Handles For Static Methods

			// a method that returns a String[]
			MethodType staticMethodType = MethodType.methodType(String[].class);
			// get a method handle on getDetails method of the class Country
			MethodHandle staticMethodHandle = publicLookup.findStatic(Country.class, "getDetails", staticMethodType);

The “findStatic()” method of the Lookup class can be used to gain access to a static method of a class. In the above example, we create a method handle for a method that returns a String array.

4. Invoking a Method Handle in Java

We already saw the “invoke()” and the “invokeWithArguments()” method in examples above to invoke the method handle for a method or a member of a class. The MethodHandle class provides another variant of invoking, the “invokeExact()” method.

4.1 The invokeExact method

The “invokeExact()” method invokes the method handle, but requires an exact type match, and does not allow any conversions on arguments or return values. A WrongMethodTypeException is thrown to indicate that the code has attempted to call a MethodHandle using the wrong MethodType.

5. Conclusion

In this example, we discussed the Java Reflection API, its performance issues, and how the MethodHandles API solves those issues. We also saw the creation of MethodTypes, MethodHandles, and the way they are used.

6. Download the source code

That was an article about Method Handles in Java.

Download
You can download the full source code of this example here: Method Handles in Java

Anmol Deep

Anmol Deep is a senior engineer currently working with a leading identity security company as a Web Developer. He has 8 years of programming experience in Java and related technologies (including functional programming and lambdas) , Python, SpringBoot, Restful architectures, shell scripts, and databases relational(MySQL, H2) and nosql solutions (OrientDB and MongoDB). He is passionate about researching all aspects of software development including technology, design patterns, automation, best practices, methodologies and tools, and love traveling and photography when not coding.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button