UnreflectHandleSupplier.java

package tools.jackson.databind.util.internal;

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
import java.util.function.Supplier;

import tools.jackson.databind.util.ClassUtil;

/**
 * Lazy memoized holder for MethodHandles.
 * Defers binding of the method handle until after access checks are suppressed
 * (which happens in a virtual method call after construction) and avoids serialization of
 * MethodHandle.
 */
public abstract class UnreflectHandleSupplier implements Supplier<MethodHandle> {
    private final MethodType asType;
    private boolean initialized;
    private Supplier<MethodHandle> delegate = this::initialize;

    public UnreflectHandleSupplier(MethodType asType) {
        this.asType = asType;
    }

    @Override
    public MethodHandle get() {
        return delegate.get();
    }

    synchronized MethodHandle initialize() {
        if (!initialized) {
            MethodHandle mh;
            try {
                mh = postprocess(unreflect());
            } catch (IllegalAccessException e) {
                throw ClassUtil.sneakyThrow(e);
            }
            delegate = () -> mh;
            initialized = true;
        }
        return delegate.get();
    }

    protected MethodHandle postprocess(MethodHandle mh) {
        if (mh == null) {
            return mh;
        }
        if (asType == null) {
            return mh.asFixedArity();
        }
        return mh.asType(asType);
    }

    protected abstract MethodHandle unreflect() throws IllegalAccessException;

    @Override
    public String toString() {
        return get().toString();
    }
}