shz.core.InterfaceProxy Maven / Gradle / Ivy
package shz.core;
import shz.core.cl.ClassLoaderHelp;
import shz.core.type.TypeHelp;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.List;
import java.util.function.Function;
@SuppressWarnings("unchecked")
public final class InterfaceProxy implements InvocationHandler {
public static final class Param {
public final Object proxy;
public final Method method;
public final Object[] args;
Param(Object proxy, Method method, Object[] args) {
this.proxy = proxy;
this.method = method;
this.args = args;
}
}
private final Function executor;
private InterfaceProxy(Function executor) {
this.executor = executor;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) {
Class> dCls = method.getDeclaringClass();
if (dCls == Object.class) {
switch (method.getName()) {
case "hashCode":
return System.identityHashCode(proxy);
case "equals":
return proxy == args[0];
case "toString":
return executor.toString();
default:
return null;
}
}
Object invoke = executor.apply(new Param(proxy, method, args));
if (invoke == null) return null;
Class> rt = method.getReturnType();
if (rt == void.class || rt == Void.class) return null;
if (!rt.isInstance(invoke)) invoke = FieldSetter.create(invoke, rt, method.getGenericReturnType());
return invoke;
}
public static T getProxy(Class cls, Function executor, boolean save) {
NullHelp.requireNonNull(executor);
List> interfaces = TypeHelp.getInterfaces(cls);
NullHelp.requireNonEmpty(interfaces);
ClassLoader cl = ClassLoaderHelp.get(cls);
if (cl != null) {
interfaces = ToList.explicitCollect(interfaces.stream().filter(c -> {
try {
return c.getClassLoader() == cl;
} catch (SecurityException ignored) {
}
try {
return c == cl.loadClass(c.getName());
} catch (ClassNotFoundException e) {
return false;
}
}), interfaces.size());
NullHelp.requireNonEmpty(interfaces);
}
if (save) System.getProperties().setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
return (T) Proxy.newProxyInstance(cl, interfaces.toArray(new Class[0]), new InterfaceProxy(executor));
}
public static T getProxy(Class cls, Function executor) {
return getProxy(cls, executor, false);
}
}