A faster alternative to Java Reflection

It also later allowed lambda expression and method reference in Java 8 as well as string concatenation in Java 9 to benefit from it.In a nutshell, the technique I’m about to better describe below leverages LambdaMetafactory and MethodHandle in order to dynamically create an implementation of Function and its single method delegates a call to the actual target method with a code defined inside of lambda body..The target method in question here is the actual getter method that has direct access to the field we want to read..Also, I should say if you are quite familiar with the nice things that came up within Java 8, you will find the below code snippets fairly easy to understand..Otherwise, it may be tricky at a glance.A peek at the homemade JavaBeanUtilThe following method is the utility used to read a value from a JavaBean field..It takes the JavaBean object and a single fieldA or even nested field separated by periods, for example, nestedJavaBean.nestedJavaBean.fieldAFor optimal performance, I’m caching the dynamically created function that is the actual way of reading the content of a given fieldName..So inside the getCachedFunction method, as you can see above, there’s a fast path leveraging the ClassValue for caching and there’s the slow createAndCacheFunction path executed only if nothing has been cached so far.The slow path will basically delegate to the createFunctions method that is returning a list of functions to be reduced by chaining them using Function::andThen..When functions are chained, you can imagine some sort of nested calls like getNestedJavaBean().getNestedJavaBean().getFieldA()..Finally, after chaining we simply put the reduced function in the cache calling cacheAndGetFunction method.Drilling a bit more into the slow path of function creation, we need to individually navigate through the field path variable by splitting it as per below:The above createFunctions method delegates the individual fieldName and its class holder type to createFunction method, which will locate the needed getter based upon javaBeanClass.getDeclaredMethods()..Once it’s located, it maps to a Tuple object (facility from Vavr library), that contains the return type of the getter method and the dynamically created function in which will act as if it was the actual getter method itself.This tuple mapping is done by createTupleWithReturnTypeAndGetter in conjunction with createCallSite method as follows:In the above two methods, I make use of a constant called LOOKUP, which’s simply a reference to MethodHandles.Lookup..With that, I can create a direct method handle based on the previously located getter method, and finally, the created MethodHandle is passed to createCallSite method whereby the lambda body for the function is produced using the LambdaMetafactory from where ultimately we can obtain the CallSite instance, which’s the function holder..Note that if I wanted to deal with setters I could use a similar approach by leveraging BiFunction instead of Function.BenchmarkIn order to measure the gains of performance, I used the ever-awesome JMH(Java Microbenchmark Harness), which will likely be part of the JDK 12..As you may know, results are bound to the platform so for reference I’ll be utilizing a single 1×6 i5-8600K 3.6GHz and Linux x86_64 as well as Oracle JDK 8u191 and GraalVM EE 1.0.0-rc9.For comparison, I basically used Apache Commons BeanUtils, a well-known library for most of Java developers, and one of its alternatives called Jodd BeanUtil in which claims to be almost 20% faster.Benchmark scenario is set as follows:The benchmark is driven by how deep we are going to retrieve some value as per the four different levels specified above.. More details

Leave a Reply