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 a {@link MethodHandle} unreflected from a
* {@link java.lang.reflect.Member}.
*<p>
* Resolution is deferred until first actual use, for two reasons:
*<ul>
* <li>Access to non-public members is only enabled by
* {@code ClassUtil.checkAndFixAccess()}, which callers apply via
* {@code AnnotatedMember.fixAccess()} <i>after</i> the owning member has been
* constructed. Unreflecting during construction could hence fail.
* </li>
* <li>Many members are introspected but never actually invoked, so the handle
* lookup is often avoidable altogether.
* </li>
* </ul>
* The resolved handle is adapted once -- to the {@link MethodType} given to the
* constructor, or {@link MethodHandle#asFixedArity()} if that is {@code null} --
* and then memoized; resolution happens at most once per holder.
*/
public abstract class UnreflectHandleSupplier implements Supplier<MethodHandle> {
private final MethodType asType;
private volatile MethodHandle cachedHandle;
public UnreflectHandleSupplier(MethodType asType) {
this.asType = asType;
}
@Override
public MethodHandle get() {
MethodHandle h = cachedHandle;
if (h == null) {
h = initialize();
}
return h;
}
private synchronized MethodHandle initialize() {
MethodHandle h = cachedHandle;
if (h == null) {
try {
h = postprocess(unreflect());
} catch (IllegalAccessException e) {
throw ClassUtil.sneakyThrow(e);
}
cachedHandle = h;
}
return h;
}
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();
}
}