ByMethodHandle.java
package space.sunqian.common.invoke;
import space.sunqian.annotations.Nonnull;
import space.sunqian.annotations.Nullable;
import space.sunqian.common.reflect.ClassKit;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
final class ByMethodHandle {
static final int MAX_STATIC_ARGS_NUM = 16;
static final int MAX_INST_ARGS_NUM = 15;
static @Nonnull Invocable newInvocable(@Nonnull Method method) {
MethodHandle handle = methodHandle(method);
boolean isStatic = ClassKit.isStatic(method);
return newInvocable(handle, isStatic);
}
private static @Nonnull MethodHandle methodHandle(@Nonnull Method method) throws InvocationException {
try {
return MethodHandles.lookup()
.unreflect(method)
// .findVirtual(
// method.getDeclaringClass(),
// method.getName(),
// MethodType.methodType(method.getReturnType(), method.getParameterTypes())
// )
//.asType(buildMethodType(method))
;
} catch (Exception e) {
throw new InvocationException(e);
}
}
static @Nonnull Invocable newInvocable(@Nonnull Constructor<?> constructor) {
MethodHandle handle = constructorHandle(constructor);
return newInvocable(handle, true);
}
private static @Nonnull MethodHandle constructorHandle(@Nonnull Constructor<?> constructor) throws InvocationException {
try {
return MethodHandles.lookup()
.unreflectConstructor(constructor)
// .findConstructor(
// constructor.getDeclaringClass(),
// MethodType.methodType(void.class, constructor.getParameterTypes())
// );
//.asType(buildMethodType(constructor))
;
} catch (Exception e) {
throw new InvocationException(e);
}
}
static @Nonnull Invocable newInvocable(@Nonnull MethodHandle handle, boolean isStatic) {
switch (handle.type().parameterCount()) {
case 0:
return new StaticInvoker0(handle);
case 1:
return isStatic ? new StaticInvoker1(handle) : new InstanceInvoker0(handle);
case 2:
return isStatic ? new StaticInvoker2(handle) : new InstanceInvoker1(handle);
case 3:
return isStatic ? new StaticInvoker3(handle) : new InstanceInvoker2(handle);
case 4:
return isStatic ? new StaticInvoker4(handle) : new InstanceInvoker3(handle);
case 5:
return isStatic ? new StaticInvoker5(handle) : new InstanceInvoker4(handle);
case 6:
return isStatic ? new StaticInvoker6(handle) : new InstanceInvoker5(handle);
case 7:
return isStatic ? new StaticInvoker7(handle) : new InstanceInvoker6(handle);
case 8:
return isStatic ? new StaticInvoker8(handle) : new InstanceInvoker7(handle);
case 9:
return isStatic ? new StaticInvoker9(handle) : new InstanceInvoker8(handle);
case 10:
return isStatic ? new StaticInvoker10(handle) : new InstanceInvoker9(handle);
case 11:
return isStatic ? new StaticInvoker11(handle) : new InstanceInvoker10(handle);
case 12:
return isStatic ? new StaticInvoker12(handle) : new InstanceInvoker11(handle);
case 13:
return isStatic ? new StaticInvoker13(handle) : new InstanceInvoker12(handle);
case 14:
return isStatic ? new StaticInvoker14(handle) : new InstanceInvoker13(handle);
case 15:
return isStatic ? new StaticInvoker15(handle) : new InstanceInvoker14(handle);
case 16:
return isStatic ? new StaticInvoker16(handle) : new InstanceInvoker15(handle);
default:
return forHandle(handle, isStatic);
}
}
private static @Nonnull Invocable forHandle(@Nonnull MethodHandle methodHandle, boolean isStatic) {
return isStatic ? new StaticInvoker(methodHandle) : new InstanceInvoker(methodHandle);
}
// public static void main(String[] args) {
// StringBuilder sb = new StringBuilder();
// for (int i = 1; i < 17; i++) {
// sb.append("case ").append(i).append(": ").append("return isStatic ? new StaticInvoker");
// sb.append(i).append("(handle) : new InstanceInvoker").append(i - 1).append("(handle);");
// sb.append(System.lineSeparator());
// }
// System.out.println(sb);
// }
private static final class StaticInvoker implements Invocable {
private final @Nonnull MethodHandle methodHandle;
private StaticInvoker(@Nonnull MethodHandle methodHandle) {
this.methodHandle = methodHandle;
}
@Override
public @Nullable Object invokeChecked(@Nullable Object inst, @Nullable Object @Nonnull ... args) throws Throwable {
return methodHandle.invokeWithArguments(args);
}
}
private static final class InstanceInvoker implements Invocable {
private final @Nonnull MethodHandle methodHandle;
private InstanceInvoker(@Nonnull MethodHandle methodHandle) {
this.methodHandle = methodHandle;
}
@Override
public @Nullable Object invokeChecked(@Nullable Object inst, @Nullable Object @Nonnull ... args) throws Throwable {
return methodHandle.invokeWithArguments(InvokeKit.toInstanceArgs(inst, args));
}
}
private static final class StaticInvoker0 implements Invocable {
private final @Nonnull MethodHandle methodHandle;
private StaticInvoker0(@Nonnull MethodHandle methodHandle) {
this.methodHandle = methodHandle;
}
@Override
public @Nullable Object invokeChecked(@Nullable Object inst, @Nullable Object @Nonnull ... args) throws Throwable {
return methodHandle.invoke();
}
}
private static final class StaticInvoker1 implements Invocable {
private final @Nonnull MethodHandle methodHandle;
private StaticInvoker1(@Nonnull MethodHandle methodHandle) {
this.methodHandle = methodHandle;
}
@Override
public @Nullable Object invokeChecked(@Nullable Object inst, @Nullable Object @Nonnull ... args) throws Throwable {
return methodHandle.invoke(args[0]);
}
}
private static final class StaticInvoker2 implements Invocable {
private final @Nonnull MethodHandle methodHandle;
private StaticInvoker2(@Nonnull MethodHandle methodHandle) {
this.methodHandle = methodHandle;
}
@Override
public @Nullable Object invokeChecked(@Nullable Object inst, @Nullable Object @Nonnull ... args) throws Throwable {
return methodHandle.invoke(args[0], args[1]);
}
}
private static final class StaticInvoker3 implements Invocable {
private final @Nonnull MethodHandle methodHandle;
private StaticInvoker3(@Nonnull MethodHandle methodHandle) {
this.methodHandle = methodHandle;
}
@Override
public @Nullable Object invokeChecked(@Nullable Object inst, @Nullable Object @Nonnull ... args) throws Throwable {
return methodHandle.invoke(args[0], args[1], args[2]);
}
}
private static final class StaticInvoker4 implements Invocable {
private final @Nonnull MethodHandle methodHandle;
private StaticInvoker4(@Nonnull MethodHandle methodHandle) {
this.methodHandle = methodHandle;
}
@Override
public @Nullable Object invokeChecked(@Nullable Object inst, @Nullable Object @Nonnull ... args) throws Throwable {
return methodHandle.invoke(args[0], args[1], args[2], args[3]);
}
}
private static final class StaticInvoker5 implements Invocable {
private final @Nonnull MethodHandle methodHandle;
private StaticInvoker5(@Nonnull MethodHandle methodHandle) {
this.methodHandle = methodHandle;
}
@Override
public @Nullable Object invokeChecked(@Nullable Object inst, @Nullable Object @Nonnull ... args) throws Throwable {
return methodHandle.invoke(args[0], args[1], args[2], args[3], args[4]);
}
}
private static final class StaticInvoker6 implements Invocable {
private final @Nonnull MethodHandle methodHandle;
private StaticInvoker6(@Nonnull MethodHandle methodHandle) {
this.methodHandle = methodHandle;
}
@Override
public @Nullable Object invokeChecked(@Nullable Object inst, @Nullable Object @Nonnull ... args) throws Throwable {
return methodHandle.invoke(args[0], args[1], args[2], args[3], args[4], args[5]);
}
}
private static final class StaticInvoker7 implements Invocable {
private final @Nonnull MethodHandle methodHandle;
private StaticInvoker7(@Nonnull MethodHandle methodHandle) {
this.methodHandle = methodHandle;
}
@Override
public @Nullable Object invokeChecked(@Nullable Object inst, @Nullable Object @Nonnull ... args) throws Throwable {
return methodHandle.invoke(args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
}
}
private static final class StaticInvoker8 implements Invocable {
private final @Nonnull MethodHandle methodHandle;
private StaticInvoker8(@Nonnull MethodHandle methodHandle) {
this.methodHandle = methodHandle;
}
@Override
public @Nullable Object invokeChecked(@Nullable Object inst, @Nullable Object @Nonnull ... args) throws Throwable {
return methodHandle.invoke(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]);
}
}
private static final class StaticInvoker9 implements Invocable {
private final @Nonnull MethodHandle methodHandle;
private StaticInvoker9(@Nonnull MethodHandle methodHandle) {
this.methodHandle = methodHandle;
}
@Override
public @Nullable Object invokeChecked(@Nullable Object inst, @Nullable Object @Nonnull ... args) throws Throwable {
return methodHandle.invoke(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]);
}
}
private static final class StaticInvoker10 implements Invocable {
private final @Nonnull MethodHandle methodHandle;
private StaticInvoker10(@Nonnull MethodHandle methodHandle) {
this.methodHandle = methodHandle;
}
@Override
public @Nullable Object invokeChecked(@Nullable Object inst, @Nullable Object @Nonnull ... args) throws Throwable {
return methodHandle.invoke(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9]);
}
}
private static final class StaticInvoker11 implements Invocable {
private final @Nonnull MethodHandle methodHandle;
private StaticInvoker11(@Nonnull MethodHandle methodHandle) {
this.methodHandle = methodHandle;
}
@Override
public @Nullable Object invokeChecked(@Nullable Object inst, @Nullable Object @Nonnull ... args) throws Throwable {
return methodHandle.invoke(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10]);
}
}
private static final class StaticInvoker12 implements Invocable {
private final @Nonnull MethodHandle methodHandle;
private StaticInvoker12(@Nonnull MethodHandle methodHandle) {
this.methodHandle = methodHandle;
}
@Override
public @Nullable Object invokeChecked(@Nullable Object inst, @Nullable Object @Nonnull ... args) throws Throwable {
return methodHandle.invoke(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11]);
}
}
private static final class StaticInvoker13 implements Invocable {
private final @Nonnull MethodHandle methodHandle;
private StaticInvoker13(@Nonnull MethodHandle methodHandle) {
this.methodHandle = methodHandle;
}
@Override
public @Nullable Object invokeChecked(@Nullable Object inst, @Nullable Object @Nonnull ... args) throws Throwable {
return methodHandle.invoke(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12]);
}
}
private static final class StaticInvoker14 implements Invocable {
private final @Nonnull MethodHandle methodHandle;
private StaticInvoker14(@Nonnull MethodHandle methodHandle) {
this.methodHandle = methodHandle;
}
@Override
public @Nullable Object invokeChecked(@Nullable Object inst, @Nullable Object @Nonnull ... args) throws Throwable {
return methodHandle.invoke(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13]);
}
}
private static final class StaticInvoker15 implements Invocable {
private final @Nonnull MethodHandle methodHandle;
private StaticInvoker15(@Nonnull MethodHandle methodHandle) {
this.methodHandle = methodHandle;
}
@Override
public @Nullable Object invokeChecked(@Nullable Object inst, @Nullable Object @Nonnull ... args) throws Throwable {
return methodHandle.invoke(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13], args[14]);
}
}
private static final class StaticInvoker16 implements Invocable {
private final @Nonnull MethodHandle methodHandle;
private StaticInvoker16(@Nonnull MethodHandle methodHandle) {
this.methodHandle = methodHandle;
}
@Override
public @Nullable Object invokeChecked(@Nullable Object inst, @Nullable Object @Nonnull ... args) throws Throwable {
return methodHandle.invoke(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13], args[14], args[15]);
}
}
private static final class InstanceInvoker0 implements Invocable {
private final @Nonnull MethodHandle methodHandle;
private InstanceInvoker0(@Nonnull MethodHandle methodHandle) {
this.methodHandle = methodHandle;
}
@Override
public @Nullable Object invokeChecked(@Nullable Object inst, @Nullable Object @Nonnull ... args) throws Throwable {
return methodHandle.invoke(inst);
}
}
private static final class InstanceInvoker1 implements Invocable {
private final @Nonnull MethodHandle methodHandle;
private InstanceInvoker1(@Nonnull MethodHandle methodHandle) {
this.methodHandle = methodHandle;
}
@Override
public @Nullable Object invokeChecked(@Nullable Object inst, @Nullable Object @Nonnull ... args) throws Throwable {
return methodHandle.invoke(inst, args[0]);
}
}
private static final class InstanceInvoker2 implements Invocable {
private final @Nonnull MethodHandle methodHandle;
private InstanceInvoker2(@Nonnull MethodHandle methodHandle) {
this.methodHandle = methodHandle;
}
@Override
public @Nullable Object invokeChecked(@Nullable Object inst, @Nullable Object @Nonnull ... args) throws Throwable {
return methodHandle.invoke(inst, args[0], args[1]);
}
}
private static final class InstanceInvoker3 implements Invocable {
private final @Nonnull MethodHandle methodHandle;
private InstanceInvoker3(@Nonnull MethodHandle methodHandle) {
this.methodHandle = methodHandle;
}
@Override
public @Nullable Object invokeChecked(@Nullable Object inst, @Nullable Object @Nonnull ... args) throws Throwable {
return methodHandle.invoke(inst, args[0], args[1], args[2]);
}
}
private static final class InstanceInvoker4 implements Invocable {
private final @Nonnull MethodHandle methodHandle;
private InstanceInvoker4(@Nonnull MethodHandle methodHandle) {
this.methodHandle = methodHandle;
}
@Override
public @Nullable Object invokeChecked(@Nullable Object inst, @Nullable Object @Nonnull ... args) throws Throwable {
return methodHandle.invoke(inst, args[0], args[1], args[2], args[3]);
}
}
private static final class InstanceInvoker5 implements Invocable {
private final @Nonnull MethodHandle methodHandle;
private InstanceInvoker5(@Nonnull MethodHandle methodHandle) {
this.methodHandle = methodHandle;
}
@Override
public @Nullable Object invokeChecked(@Nullable Object inst, @Nullable Object @Nonnull ... args) throws Throwable {
return methodHandle.invoke(inst, args[0], args[1], args[2], args[3], args[4]);
}
}
private static final class InstanceInvoker6 implements Invocable {
private final @Nonnull MethodHandle methodHandle;
private InstanceInvoker6(@Nonnull MethodHandle methodHandle) {
this.methodHandle = methodHandle;
}
@Override
public @Nullable Object invokeChecked(@Nullable Object inst, @Nullable Object @Nonnull ... args) throws Throwable {
return methodHandle.invoke(inst, args[0], args[1], args[2], args[3], args[4], args[5]);
}
}
private static final class InstanceInvoker7 implements Invocable {
private final @Nonnull MethodHandle methodHandle;
private InstanceInvoker7(@Nonnull MethodHandle methodHandle) {
this.methodHandle = methodHandle;
}
@Override
public @Nullable Object invokeChecked(@Nullable Object inst, @Nullable Object @Nonnull ... args) throws Throwable {
return methodHandle.invoke(inst, args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
}
}
private static final class InstanceInvoker8 implements Invocable {
private final @Nonnull MethodHandle methodHandle;
private InstanceInvoker8(@Nonnull MethodHandle methodHandle) {
this.methodHandle = methodHandle;
}
@Override
public @Nullable Object invokeChecked(@Nullable Object inst, @Nullable Object @Nonnull ... args) throws Throwable {
return methodHandle.invoke(inst, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]);
}
}
private static final class InstanceInvoker9 implements Invocable {
private final @Nonnull MethodHandle methodHandle;
private InstanceInvoker9(@Nonnull MethodHandle methodHandle) {
this.methodHandle = methodHandle;
}
@Override
public @Nullable Object invokeChecked(@Nullable Object inst, @Nullable Object @Nonnull ... args) throws Throwable {
return methodHandle.invoke(inst, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]);
}
}
private static final class InstanceInvoker10 implements Invocable {
private final @Nonnull MethodHandle methodHandle;
private InstanceInvoker10(@Nonnull MethodHandle methodHandle) {
this.methodHandle = methodHandle;
}
@Override
public @Nullable Object invokeChecked(@Nullable Object inst, @Nullable Object @Nonnull ... args) throws Throwable {
return methodHandle.invoke(inst, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9]);
}
}
private static final class InstanceInvoker11 implements Invocable {
private final @Nonnull MethodHandle methodHandle;
private InstanceInvoker11(@Nonnull MethodHandle methodHandle) {
this.methodHandle = methodHandle;
}
@Override
public @Nullable Object invokeChecked(@Nullable Object inst, @Nullable Object @Nonnull ... args) throws Throwable {
return methodHandle.invoke(inst, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10]);
}
}
private static final class InstanceInvoker12 implements Invocable {
private final @Nonnull MethodHandle methodHandle;
private InstanceInvoker12(@Nonnull MethodHandle methodHandle) {
this.methodHandle = methodHandle;
}
@Override
public @Nullable Object invokeChecked(@Nullable Object inst, @Nullable Object @Nonnull ... args) throws Throwable {
return methodHandle.invoke(inst, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11]);
}
}
private static final class InstanceInvoker13 implements Invocable {
private final @Nonnull MethodHandle methodHandle;
private InstanceInvoker13(@Nonnull MethodHandle methodHandle) {
this.methodHandle = methodHandle;
}
@Override
public @Nullable Object invokeChecked(@Nullable Object inst, @Nullable Object @Nonnull ... args) throws Throwable {
return methodHandle.invoke(inst, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12]);
}
}
private static final class InstanceInvoker14 implements Invocable {
private final @Nonnull MethodHandle methodHandle;
private InstanceInvoker14(@Nonnull MethodHandle methodHandle) {
this.methodHandle = methodHandle;
}
@Override
public @Nullable Object invokeChecked(@Nullable Object inst, @Nullable Object @Nonnull ... args) throws Throwable {
return methodHandle.invoke(inst, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13]);
}
}
private static final class InstanceInvoker15 implements Invocable {
private final @Nonnull MethodHandle methodHandle;
private InstanceInvoker15(@Nonnull MethodHandle methodHandle) {
this.methodHandle = methodHandle;
}
@Override
public @Nullable Object invokeChecked(@Nullable Object inst, @Nullable Object @Nonnull ... args) throws Throwable {
return methodHandle.invoke(inst, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13], args[14]);
}
}
// public static void main(String[] args) {
// StringBuilder sb = new StringBuilder();
// appendImpl(sb, 17, true);
// appendImpl(sb, 16, false);
// System.out.println(sb);
// }
//
// private static void appendImpl(StringBuilder sb, int count, boolean isStatic) {
// String className = (isStatic ? "Static" : "Instance") + "Invoker";
// for (int i = 0; i < count; i++) {
// sb.append("private static final class ").append(className).append(i).append(" implements Invocable {");
// sb.append(System.lineSeparator());
// sb.append("private final @Nonnull MethodHandle methodHandle;");
// sb.append(System.lineSeparator());
// sb.append("private ").append(className).append(i).append("(@Nonnull MethodHandle methodHandle) {this.methodHandle = methodHandle;}");
// sb.append(System.lineSeparator());
// sb.append("@Override public @Nullable Object invokeChecked(@Nullable Object inst, @Nullable Object @Nonnull ... args) throws Throwable {");
// sb.append(System.lineSeparator());
// appendCall(sb, i, isStatic);
// sb.append(System.lineSeparator()).append("}");
// sb.append(System.lineSeparator()).append("}");
// }
// sb.append(System.lineSeparator());
// }
//
// private static void appendCall(StringBuilder sb, int i, boolean isStatic) {
// sb.append("return methodHandle.invoke(");
// boolean isFirst = true;
// if (!isStatic) {
// sb.append("inst");
// isFirst = false;
// }
// for (int j = 0; j < i; j++) {
// if (!isFirst) {
// sb.append(",");
// }
// sb.append("args[").append(j).append("]");
// isFirst = false;
// }
// sb.append(");");
// }
private ByMethodHandle() {
}
}