ByReflection.java

package space.sunqian.common.invoke;

import space.sunqian.annotations.Nonnull;
import space.sunqian.annotations.Nullable;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

final class ByReflection {

    static @Nonnull Invocable newInvocable(@Nonnull Constructor<?> constructor) {
        return new ForConstructor(constructor);
    }

    static @Nonnull Invocable newInvocable(@Nonnull Method method) {
        return new ForMethod(method);
    }

    private static final class ForConstructor implements Invocable {

        private final @Nonnull Constructor<?> constructor;

        private ForConstructor(@Nonnull Constructor<?> constructor) {
            this.constructor = constructor;
        }

        @Override
        public @Nonnull Object invoke(
            @Nullable Object inst, @Nullable Object @Nonnull ... args
        ) throws InvocationException {
            try {
                return constructor.newInstance(args);
            } catch (Throwable e) {
                throw new InvocationException(e);
            }
        }

        @Override
        public Object invokeChecked(
            @Nullable Object inst, @Nullable Object @Nonnull ... args
        ) throws Throwable {
            try {
                return constructor.newInstance(args);
            } catch (InvocationTargetException e) {
                throw e.getCause();
            }
        }
    }

    private static final class ForMethod implements Invocable {

        private final @Nonnull Method method;

        private ForMethod(@Nonnull Method method) {
            this.method = method;
        }

        @Override
        public @Nullable Object invoke(
            @Nullable Object inst, @Nullable Object @Nonnull ... args
        ) throws InvocationException {
            try {
                return method.invoke(inst, args);
            } catch (Throwable e) {
                throw new InvocationException(e);
            }
        }

        @Override
        public @Nullable Object invokeChecked(
            @Nullable Object inst, @Nullable Object @Nonnull ... args
        ) throws Throwable {
            try {
                return method.invoke(inst, args);
            } catch (InvocationTargetException e) {
                throw e.getCause();
            }
        }
    }

    private ByReflection() {
    }
}