Sunday, May 29, 2022

Java_18_Features - Reimplement Core Reflection with Method Handles

If you have a lot to do with Java reflection, you will know that there is always more than one way to go. For example, to read the private value field of a String via reflection.

Sometimes We want to do Java reflection, such as reading a private id field of a Person object’s class via reflection.

package org.java.mag.j18.reflection; import lombok.Builder; import lombok.Data; @Data @Builder public class Person { private Long id; private String name; }
Code language: plaintext (plaintext)

Surprisingly, there are two ways to do that. First, I can use core reflection, as follows:

private static Long getLongId(Object obj) throws Exception { Field id = obj.getClass().getDeclaredField("id"); id.setAccessible(true); return (Long) id.get(obj); }
Code language: plaintext (plaintext)

Alternatively, I can use method handles, as shown below.

private static Long getLongId2(Object obj) throws Exception { VarHandle handle = MethodHandles.privateLookupIn(Person.class, MethodHandles.lookup()) .findVarHandle(Person.class, "id", Long.class); return (Long) handle.get(obj); }
Code language: plaintext (plaintext)

If you call both options from main, you’ll see that they print the same value, verifying that they both work

public static void main(String[] args) throws Exception { Person person = Person.builder() .id(2L) .name("Mohamed Taman") .build(); System.out.println("Person Id (Core reflection): " + getLongId(person)); System.out.println("Person Id (method handles): " + getLongId2(person)); } Person Id (Core reflection): 2 Person Id (method handles): 2

A third hidden option happens under the hood: leveraging additional native JVM methods used by the core reflection for the first few calls after starting the JVM. After a while, the JVM begins compiling and optimizing the Java reflection bytecode.

Maintaining all three of these options would necessitate a significant amount of effort from the JDK team. As a result, the core reflection reimplementation with method handles, as in JEP 416, now reimplements lang.reflect.Method, Constructor, and Field on top of java.lang.invoke method handles. 

The use of method handles as the underlying mechanism for reflection reduces the maintenance and development costs of the java.lang.reflect and java.lang.invoke APIs; thus, it is good for the future of the platform.


You may also like

a
Kubernetes AWS Java Coding Question
Microservices Core Java Python
Spring Framework AI/MLSpring Boot