下面列出了怎么用java.lang.invoke.MethodHandles的API类实例代码及写法,或者点击链接到github查看源代码。
public static void main(String[] args) throws Throwable {
l = MethodHandles.lookup();
h = l.findVirtual(LambdaReceiver_A.class, "f", mt(int.class));
MethodType X = mt(int.class, LambdaReceiver.class);
MethodType A = mt(int.class, LambdaReceiver_A.class);
MethodType mti = mt(IA.class);
CallSite cs = LambdaMetafactory.metafactory(l, "m", mti,A,h,X);
IA p = (IA)cs.dynamicInvoker().invoke();
LambdaReceiver_A lra = new LambdaReceiver_A();
try {
p.m(lra);
} catch (ClassCastException cce) {
return;
}
throw new AssertionError("CCE expected");
}
static MethodHandle linkMissingBeanMember(final LinkRequest linkRequest, final LinkerServices linkerServices) throws Exception {
final CallSiteDescriptor desc = linkRequest.getCallSiteDescriptor();
final String operand = NashornCallSiteDescriptor.getOperand(desc);
switch (NashornCallSiteDescriptor.getStandardOperation(desc)) {
case GET:
if (NashornCallSiteDescriptor.isOptimistic(desc)) {
return adaptThrower(MethodHandles.insertArguments(THROW_OPTIMISTIC_UNDEFINED, 0, NashornCallSiteDescriptor.getProgramPoint(desc)), desc);
} else if (operand != null) {
return getInvocation(EMPTY_PROP_GETTER, linkerServices, desc);
}
return getInvocation(EMPTY_ELEM_GETTER, linkerServices, desc);
case SET:
final boolean strict = NashornCallSiteDescriptor.isStrict(desc);
if (strict) {
return adaptThrower(bindOperand(THROW_STRICT_PROPERTY_SETTER, operand), desc);
} else if (operand != null) {
return getInvocation(EMPTY_PROP_SETTER, linkerServices, desc);
}
return getInvocation(EMPTY_ELEM_SETTER, linkerServices, desc);
default:
throw new AssertionError("unknown call type " + desc);
}
}
private long uniqueInstanceMethodHandleInstanceFieldWriteAccessInvokeOnly(int spins) throws Throwable {
ReflectionTarget[] targets = new ReflectionTarget[spins];
MethodHandle[] fields = new MethodHandle[spins];
for (int i = 0; i < spins; i++) {
ClassLoader loader = new URLClassLoader(new URL[]{ classpathDirectory.toURI().toURL() });
Class<?> clazz = loader.loadClass(targetClassName);
targets[i] = (ReflectionTarget) MethodHandles.lookup().findConstructor(clazz, MethodType.methodType(void.class)).invoke();
fields[i] = MethodHandles.lookup().findSetter(clazz, instanceField, Object.class);
}
Object object = new Object();
long start = System.nanoTime();
for (int i = 0; i < spins; i++) {
fields[i].invoke(targets[i], object);
}
long end = System.nanoTime();
return end - start;
}
public static void main(String[] args) {
String str = "*****\n Hi\n \tHello Pankaj\rHow are you?\n*****";
// 1. public String indent(int n)
System.out.println(str.indent(0));
System.out.println(str.indent(3));
System.out.println(str.indent(-3));
// 2. public <R> R transform(Function<? super String,? extends R> f)
String s = "Hi,Hello,Howdy";
List<String> strList = s.transform(s1 -> {return Arrays.asList(s1.split(","));});
System.out.println(strList);
//Java 12 String implements Constable, ConstantDesc - hence two new methods
// 3. public Optional<String> describeConstable()
String so = "Hello";
Optional<String> os = so.describeConstable();
System.out.println(os);
System.out.println(os.get());
// 4. public String resolveConstantDesc(MethodHandles.Lookup lookup)
String so1 = "Hello";
System.out.println(so1.resolveConstantDesc(MethodHandles.lookup()));
}
private Handle generateBootstrapMethod(Handle h) {
String bootstrapName = "bootstrapMethod";
MethodType bootstrapType = MethodType.methodType(CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class);
MethodVisitor bmv = cv.visitMethod(ACC_PUBLIC | ACC_STATIC, bootstrapName, bootstrapType.toMethodDescriptorString(), null, null);
bmv.visitCode();
String constCallSite = "java/lang/invoke/ConstantCallSite";
bmv.visitTypeInsn(NEW, constCallSite);
bmv.visitInsn(DUP);
bmv.visitLdcInsn(h);
bmv.visitMethodInsn(INVOKESPECIAL, constCallSite, "<init>", "(Ljava/lang/invoke/MethodHandle;)V", false);
bmv.visitInsn(ARETURN);
bmv.visitMaxs(0,0);
bmv.visitEnd();
return new Handle(H_INVOKESTATIC, ownerClassName, bootstrapName, bootstrapType.toMethodDescriptorString());
}
@Test
void dumpOpenSslInfoDoNotThrowStackOverFlowError() throws Throwable {
assumeThat(OpenSsl.isAvailable()).isTrue();
System.setProperty("com.linecorp.armeria.dumpOpenSslInfo", "true");
// There's a chance that Flags.useOpenSsl() is already called by other test cases, which means that
// we cannot set dumpOpenSslInfo. So we use our own class loader to load the Flags class.
final FlagsClassLoader classLoader = new FlagsClassLoader();
final Class<?> flags = classLoader.loadClass("com.linecorp.armeria.common.Flags");
final Lookup lookup = MethodHandles.publicLookup();
final MethodHandle useOpenSslMethodHandle = lookup.findStatic(flags, "useOpenSsl",
MethodType.methodType(boolean.class));
useOpenSslMethodHandle.invoke(); // Call Flags.useOpenSsl();
final MethodHandle dumpOpenSslInfoMethodHandle =
lookup.findStatic(flags, "dumpOpenSslInfo", MethodType.methodType(boolean.class));
// // Call Flags.dumpOpenSslInfo();
assertThat(dumpOpenSslInfoMethodHandle.invoke()).isSameAs(Boolean.TRUE);
}
@Test
public void testReturnOnStack() throws Throwable {
MethodHandles.Lookup l = MethodHandles.lookup();
MethodHandle consumeIdentity = l.findStatic(
PermuteArgsReturnVoidTest.class, "consumeIdentity",
MethodType.methodType(String.class, String.class, int.class, int.class));
MethodHandle consumeVoid = l.findStatic(
PermuteArgsReturnVoidTest.class, "consumeVoid",
MethodType.methodType(void.class, String.class, int.class, int.class));
MethodHandle f = MethodHandles.foldArguments(consumeIdentity, consumeVoid);
MethodHandle p = MethodHandles.permuteArguments(f, MethodType.methodType(String.class, String.class, int.class, int.class), 0, 2, 1);
String s = (String) p.invoke("IN", 0, 0);
Assert.assertEquals(s.getClass(), String.class);
Assert.assertEquals(s, "IN");
}
@BeforeClass
public void setup() throws Exception {
vhFinalField = MethodHandles.lookup().findVarHandle(
VarHandleTestAccessBoolean.class, "final_v", boolean.class);
vhField = MethodHandles.lookup().findVarHandle(
VarHandleTestAccessBoolean.class, "v", boolean.class);
vhStaticFinalField = MethodHandles.lookup().findStaticVarHandle(
VarHandleTestAccessBoolean.class, "static_final_v", boolean.class);
vhStaticField = MethodHandles.lookup().findStaticVarHandle(
VarHandleTestAccessBoolean.class, "static_v", boolean.class);
vhArray = MethodHandles.arrayElementVarHandle(boolean[].class);
}
private MethodHandle introspectConstructor()
{
try {
Method m = _type.getMethod("valueOf", String.class);
Objects.requireNonNull(m);
m.setAccessible(true);
MethodHandle mh = MethodHandles.lookup().unreflect(m);
mh = mh.asType(MethodType.methodType(Object.class, String.class));
return mh;
} catch (Exception e) {
throw new H3ExceptionIn(_type.getName() + ": " + e.getMessage(), e);
}
}
private final MethodHandle findReadWriteObjectForSerialization(Class<?> cl,
String methodName,
Class<?> streamClass) {
if (!Serializable.class.isAssignableFrom(cl)) {
return null;
}
try {
Method meth = cl.getDeclaredMethod(methodName, streamClass);
int mods = meth.getModifiers();
if (meth.getReturnType() != Void.TYPE ||
Modifier.isStatic(mods) ||
!Modifier.isPrivate(mods)) {
return null;
}
meth.setAccessible(true);
return MethodHandles.lookup().unreflect(meth);
} catch (NoSuchMethodException ex) {
return null;
} catch (IllegalAccessException ex1) {
throw new InternalError("Error", ex1);
}
}
private MethodHandle getTestMH(Class clazz, String methodName,
Object param, boolean isNegativeTest)
throws Exception {
MethodType mType = (param != null)
? MethodType.genericMethodType(1)
: MethodType.methodType(String.class);
MethodHandles.Lookup lookup = MethodHandles.lookup();
if (!isNegativeTest) {
return methodName.equals("staticMethod")
? lookup.findStatic(clazz, methodName, mType)
: lookup.findVirtual(clazz, methodName, mType);
} else {
return methodName.equals("staticMethod")
? lookup.findVirtual(clazz, methodName, mType)
: lookup.findStatic(clazz, methodName, mType);
}
}
private static MethodHandle forSpreadCall(MethodHandle mh, MethodType type) {
int expectedParameters = mh.type().parameterCount();
int actualParameters = type.parameterCount();
if (!mh.isVarargsCollector() || !mh.type().parameterType(expectedParameters - 1).equals(Object[].class)) {
throw new WrongMethodTypeException("Not Object[] var-args collector");
}
if (expectedParameters > actualParameters) {
throw new WrongMethodTypeException("Too few arguments");
}
if (expectedParameters < actualParameters) {
int fixedCount = actualParameters - expectedParameters;
int firstFixed = expectedParameters - 1;
List<Class<?>> fixed = type.parameterList().subList(firstFixed, firstFixed + fixedCount);
mh = MethodHandles.collectArguments(mh, firstFixed, combineArraysMH);
mh = MethodHandles.collectArguments(mh, firstFixed, toObjectArray(fixed));
}
return mh.asType(type);
}
/**
* Finds and returns a MethodHandle for the default constructor of the given class, {@code clazz}.
*
* @param clazz
* the class
* @return a MethodHandle for the default constructor. Returns {@code null} if the class does not
* have a public no-argument constructor.
*/
public static MethodHandle findDefaultConstructor(Class<?> clazz) {
MethodHandle methodHandle = null;
try {
Constructor<?> constructor = clazz.getConstructor();
methodHandle = MethodHandles.publicLookup().unreflectConstructor(constructor);
} catch (NoSuchMethodException | SecurityException | IllegalAccessException e) {
// No default constructor
}
return methodHandle;
}
public static void main(String[] args) throws Exception {
MethodHandles.lookup()
.findStaticGetter(Intf.class, "i", int.class)
.getClass(); // null check
System.out.println("TEST PASSED");
}
@Test
public void testFindSpecial() throws Throwable {
MethodHandles.Lookup lookup = (MethodHandles.Lookup)t3.getDeclaredMethod("getLookup").invoke(null);
MethodHandle mh = lookup.findSpecial(t1, "m", MethodType.methodType(int.class), t3);
int result = (int)mh.invoke(t3.newInstance());
assertEquals(result, 1); // T1.m should be invoked.
}
public void test() throws Throwable {
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodType mt = MethodType.methodType(void.class);
try {
Class<?> checkInittedHolder = TestPrivateMemberPackageSibling.class;
// Original model: checkInittedHolder = Class.class;
// Not using Class.checkInitted because it could change without notice.
MethodHandle mh = lookup.findStatic(checkInittedHolder, "checkInitted", mt);
throw new RuntimeException("IllegalAccessException not thrown");
} catch (IllegalAccessException e) {
// okay
System.out.println("Expected exception: " + e.getMessage());
}
}
private NashornCallSiteDescriptor(final MethodHandles.Lookup lookup, final String operator, final String operand,
final MethodType methodType, final int flags) {
this.lookup = lookup;
this.operator = operator;
this.operand = operand;
this.methodType = methodType;
this.flags = flags;
}
@Override
public MethodHandle setter(final MethodHandles.Lookup explicitLookup, final Class<?> clazz, final String name, final Class<?> type) {
try {
final MethodHandle mh = explicitLookup.findSetter(clazz, name, type);
return debug(mh, "setter", explicitLookup, clazz, name, type);
} catch (final NoSuchFieldException | IllegalAccessException e) {
throw new LookupException(e);
}
}
@Test
public void whenVariableHandleForPublicVariableIsCreated_ThenItIsInitializedProperly() throws NoSuchFieldException, IllegalAccessException {
VarHandle PUBLIC_TEST_VARIABLE = MethodHandles
.lookup()
.in(VariableHandlesUnitTest.class)
.findVarHandle(VariableHandlesUnitTest.class, "publicTestVariable", int.class);
assertEquals(1, PUBLIC_TEST_VARIABLE.coordinateTypes().size());
assertEquals(VariableHandlesUnitTest.class, PUBLIC_TEST_VARIABLE.coordinateTypes().get(0));
}
private static NashornCallSiteDescriptor get(final MethodHandles.Lookup lookup, final String operator, final String operand, final MethodType methodType, final int flags) {
final NashornCallSiteDescriptor csd = new NashornCallSiteDescriptor(lookup, operator, operand, methodType, flags);
// Many of these call site descriptors are identical (e.g. every getter for a property color will be
// "dyn:getProp:color(Object)Object", so it makes sense canonicalizing them.
final ConcurrentMap<NashornCallSiteDescriptor, NashornCallSiteDescriptor> classCanonicals = canonicals.get(lookup.lookupClass());
final NashornCallSiteDescriptor canonical = classCanonicals.putIfAbsent(csd, csd);
return canonical != null ? canonical : csd;
}
private RpcMethod(INSTANCE instance, Method method, String[] parameterNames,String methodName,
boolean returnTypeJdk9PublisherFlag, boolean returnTypeReactivePublisherFlag,
boolean returnRxjava3ObservableFlag, boolean returnRxjava3FlowableFlag) {
this.instance = instance;
this.method = method;
this.methodName = methodName;
this.parameterNames = parameterNames;
this.returnTypeJdk9PublisherFlag = returnTypeJdk9PublisherFlag;
this.returnTypeReactivePublisherFlag = returnTypeReactivePublisherFlag;
this.returnRxjava3ObservableFlag = returnRxjava3ObservableFlag;
this.returnRxjava3FlowableFlag = returnRxjava3FlowableFlag;
this.returnCompletableFutureFlag = CompletableFuture.class.isAssignableFrom(method.getReturnType());
this.returnCompletionStageFlag = CompletionStage.class.isAssignableFrom(method.getReturnType());
this.returnFutureFlag = Future.class.isAssignableFrom(method.getReturnType());
this.parameterTypes = method.getParameterTypes();
if(returnTypeJdk9PublisherFlag || returnTypeReactivePublisherFlag
|| returnRxjava3ObservableFlag || returnRxjava3FlowableFlag
|| returnCompletableFutureFlag || returnCompletionStageFlag || returnFutureFlag){
this.genericReturnType = getParameterizedType(method);
}else {
this.genericReturnType = method.getGenericReturnType();
}
this.innerMethodFlag = RpcServerInstance.isRpcInnerClass(method.getDeclaringClass());
this.parameterTypeDescriptorName = Stream.of(parameterTypes)
.map(Class::getSimpleName)
.collect(Collectors.joining(","));
this.methodDescriptorName = getMethodDescriptorName(method);
this.parameterCount = method.getParameterCount();
MethodHandle methodHandle;
try {
MethodHandles.Lookup publicLookup = MethodHandles.publicLookup();
MethodType methodType = MethodType.methodType(method.getReturnType(), method.getParameterTypes());
methodHandle = publicLookup.findVirtual(method.getDeclaringClass(), method.getName(), methodType);
} catch (NoSuchMethodException | IllegalAccessException e) {
methodHandle = null;
}
this.methodHandle = methodHandle;
}
private void runTest() {
Helper.clear();
Object[] args = Helper.randomArgs(
argsCount, thrower.type().parameterArray());
Object arg0 = Helper.MISSING_ARG;
Object arg1 = testCase.thrown;
if (argsCount > 0) {
arg0 = args[0];
}
if (argsCount > 1) {
args[1] = arg1;
}
Asserts.assertEQ(nargs, thrower.type().parameterCount());
if (argsCount < nargs) {
Object[] appendArgs = {arg0, arg1};
appendArgs = Arrays.copyOfRange(appendArgs, argsCount, nargs);
thrower = MethodHandles.insertArguments(
thrower, argsCount, appendArgs);
}
Asserts.assertEQ(argsCount, thrower.type().parameterCount());
MethodHandle target = MethodHandles.catchException(
testCase.filter(thrower), testCase.throwableClass,
testCase.filter(catcher));
Asserts.assertEQ(thrower.type(), target.type());
Asserts.assertEQ(argsCount, target.type().parameterCount());
Object returned;
try {
returned = target.invokeWithArguments(args);
} catch (Throwable ex) {
testCase.assertCatch(ex);
returned = ex;
}
testCase.assertReturn(returned, arg0, arg1, dropped, args);
}
/**
* Set MOP based constructor invocation path.
*/
@Override
public void setMetaClassCallHandleIfNeeded(boolean standardMetaClass) {
if (handle != null) return;
useMetaClass = true;
if (LOG_ENABLED) LOG.info("set meta class invocation path");
handle = MOP_INVOKE_CONSTRUCTOR.bindTo(mc);
handle = handle.asCollector(Object[].class, targetType.parameterCount() - 1);
handle = MethodHandles.dropArguments(handle, 0, Class.class);
if (LOG_ENABLED) LOG.info("create collector for arguments");
}
@Override
public MethodHandle findStatic(final MethodHandles.Lookup explicitLookup, final Class<?> clazz, final String name, final MethodType type) {
try {
return explicitLookup.findStatic(clazz, name, type);
} catch (final NoSuchMethodException | IllegalAccessException e) {
throw new LookupException(e);
}
}
@Override
public MethodHandle findSpecial(final MethodHandles.Lookup explicitLookup, final Class<?> clazz, final String name, final MethodType type, final Class<?> thisClass) {
try {
final MethodHandle mh = explicitLookup.findSpecial(clazz, name, type, thisClass);
return debug(mh, "findSpecial", explicitLookup, clazz, name, type);
} catch (final NoSuchMethodException | IllegalAccessException e) {
throw new LookupException(e);
}
}
public static void main(String[] args) throws Throwable {
l = MethodHandles.lookup();
h = l.findVirtual(T8032697_A.class, "f", mt(int.class));
if (mf(mt(I.class, T8032697.class), mt(int.class))) throw new AssertionError("Error: Should work");
if (mf(mt(IA.class), mt(int.class, T8032697.class))) throw new AssertionError("Error: Should work");
if (!mf(mt(I.class, T8032697_A.class), mt(int.class))) throw new AssertionError("Error: Should fail");
if (!mf(mt(IA.class), mt(int.class, T8032697_A.class))) throw new AssertionError("Error: Should fail");
}
/**
* Construct a new linker call site.
* @param name Name of method.
* @param type Method type.
* @param flags Call site specific flags.
* @return New LinkerCallSite.
*/
static LinkerCallSite newLinkerCallSite(final MethodHandles.Lookup lookup, final String name, final MethodType type,
final int flags) {
final NashornCallSiteDescriptor desc = NashornCallSiteDescriptor.get(lookup, name, type, flags);
if (desc.isProfile()) {
return ProfilingLinkerCallSite.newProfilingLinkerCallSite(desc);
}
if (desc.isTrace()) {
return new TracingLinkerCallSite(desc);
}
return new LinkerCallSite(desc);
}
private void handleNullWithoutBoolean() {
if (handle != null || args[0] != null) return;
if (staticTargetType.isPrimitive()) {
handle = MethodHandles.insertArguments(GROOVY_CAST_EXCEPTION, 1, staticTargetType);
// need to call here here because we used the static target type
// it won't be done otherwise because handle.type() == callSite.type()
castAndSetGuards();
} else {
handle = MethodHandles.identity(staticSourceType);
}
}
/**
* Composes the invocation, switchpoint, and the guard into a composite method handle that knows how to fall back.
* @param switchpointFallback the fallback method handle in case switchpoint is invalidated.
* @param guardFallback the fallback method handle in case guard returns false.
* @param catchFallback the fallback method in case the exception handler triggers
* @return a composite method handle.
*/
public MethodHandle compose(final MethodHandle guardFallback, final MethodHandle switchpointFallback, final MethodHandle catchFallback) {
final MethodHandle guarded =
guard == null ?
invocation :
MethodHandles.guardWithTest(
guard,
invocation,
guardFallback);
final MethodHandle catchGuarded =
exception == null ?
guarded :
MH.catchException(
guarded,
exception,
MethodHandles.dropArguments(
catchFallback,
0,
exception));
if (switchPoints == null) {
return catchGuarded;
}
MethodHandle spGuarded = catchGuarded;
for (final SwitchPoint sp : switchPoints) {
spGuarded = sp.guardWithTest(spGuarded, switchpointFallback);
}
return spGuarded;
}
private static MethodHandle unbox(Wrapper wrap, int kind) {
// kind 0 -> strongly typed with NPE
// kind 1 -> strongly typed but zero for null,
// kind 2 -> asType rules: accept multiple box types but only widening conversions with NPE
// kind 3 -> explicitCastArguments rules: allow narrowing conversions, zero for null
WrapperCache cache = UNBOX_CONVERSIONS[kind];
MethodHandle mh = cache.get(wrap);
if (mh != null) {
return mh;
}
// slow path
switch (wrap) {
case OBJECT:
case VOID:
throw new IllegalArgumentException("unbox "+wrap);
}
// look up the method
String name = "unbox" + wrap.wrapperSimpleName();
MethodType type = unboxType(wrap, kind);
try {
mh = IMPL_LOOKUP.findStatic(THIS_CLASS, name, type);
} catch (ReflectiveOperationException ex) {
mh = null;
}
if (mh != null) {
if (kind > 0) {
boolean cast = (kind != 2);
mh = MethodHandles.insertArguments(mh, 1, cast);
}
if (kind == 1) { // casting but exact (null -> zero)
mh = mh.asType(unboxType(wrap, 0));
}
return cache.put(wrap, mh);
}
throw new IllegalArgumentException("cannot find unbox adapter for " + wrap
+ (kind <= 1 ? " (exact)" : kind == 3 ? " (cast)" : ""));
}