📜 ⬆️ ⬇️

Dynamic generation of proxy classes in Java

Probably every java developer will sooner or later need to use proxy classes.
Under the cut are simple examples made using the JDK proxy, cglib, javassist and byte buddy.


image

We set ourselves the most simple task:



User class to experiment on
public class User implements IUser { private final String name; public User() { this(null); } public User(String name) { this.name = name; } @Override public String getName() { return name; } } 

1 Standard Tools - JDK proxy


Imports
 import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; 

 User user = new User(""); InvocationHandler handler = (proxy, method, args) -> { if(method.getName().equals("getName")){ return ((String)method.invoke(user, args)).toUpperCase(); } return method.invoke(user, args); }; IUser userProxy = (IUser) Proxy.newProxyInstance(user.getClass().getClassLoader(), User.class.getInterfaces(), handler); assertEquals("", userProxy.getName()); 

The disadvantage is that we can create a proxy class only that implements the interfaces of the class User. Ie you can not cast a proxy class in User


2 cglib


Imports
 import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; 

 User user = new User(""); MethodInterceptor handler = (obj, method , args, proxy) -> { if(method.getName().equals("getName")){ return ((String)proxy.invoke(user, args)).toUpperCase() ; } return proxy.invoke(user, args); }; User userProxy = (User) Enhancer.create(User.class, handler); assertEquals("", userProxy.getName()); 

3 javassist


Imports
 import javassist.util.proxy.MethodHandler; import javassist.util.proxy.ProxyFactory; import javassist.util.proxy.ProxyObject; 

 User user = new User(""); MethodHandler handler = (self, overridden, forwarder, args) -> { if(overridden.getName().equals("getName")){ return ((String)overridden.invoke(user, args)).toUpperCase(); } return overridden.invoke(user, args); }; ProxyFactory factory = new ProxyFactory(); factory.setSuperclass(User.class); Object instance = factory.createClass().newInstance(); ((ProxyObject) instance).setHandler(handler); User userProxy = (User) instance; assertEquals("", userProxy.getName()); 

4 byte buddy


Imports
 import net.bytebuddy.ByteBuddy; import net.bytebuddy.implementation.MethodDelegation; import static net.bytebuddy.matcher.ElementMatchers.named; 

 User user = new User(""); User userProxy = new ByteBuddy() .subclass(User.class) .method(named("getName")) .intercept(MethodDelegation.to(new MyInterceptor(user))) .make() .load(User.class.getClassLoader()) .getLoaded() .newInstance(); assertEquals("", userProxy.getName()); 

MyInterceptor
 public class MyInterceptor { User user; public MyInterceptor(User user) { this.user = user; } public String getName() { return user.getName().toUpperCase(); } } 

Productivity, simplicity, modernity - choose for yourself what suits your project more.


For performance comparison, I propose to read the article.
Testing the performance of 4 Java runtime code generators: cglib, javassist, JDK proxy & Byte Buddy


')

Source: https://habr.com/ru/post/348906/


All Articles