/** Invokes a given method via {@link Method#invoke(Object, Object...)}. */ default Object invoke(ResolvedJavaMethod method, Object receiver, Object... args) { try { JavaType[] parameterTypes = method.toParameterTypes(); Class<?>[] parameterClasses = new Class<?>[parameterTypes.length]; for (int i = 0; i < parameterClasses.length; ++i) { JavaType type = parameterTypes[i]; if (type.getJavaKind() != JavaKind.Object) { parameterClasses[i] = type.getJavaKind().toJavaClass(); } else { parameterClasses[i] = resolveClassForSnippet(parameterTypes[i]); } } Class<?> c = resolveClassForSnippet(method.getDeclaringClass()); if (method.isConstructor()) { Constructor<?> javaConstructor = c.getDeclaredConstructor(parameterClasses); javaConstructor.setAccessible(true); return javaConstructor.newInstance(args); } else { Method javaMethod = c.getDeclaredMethod(method.getName(), parameterClasses); javaMethod.setAccessible(true); return javaMethod.invoke(receiver, args); } } catch (IllegalAccessException | InstantiationException | InvocationTargetException | ClassNotFoundException | NoSuchMethodException ex) { throw new IllegalArgumentException(ex); } }
/** * Gets the method bridged to by a {@linkplain ResolvedJavaMethod#isBridge() bridge} method. The * value returned is the method called by {@code method} that has the same name as {@code bridge}. * * @param bridge a bridge method * @return the method called by {@code bridge} whose name is the same as {@code bridge.getName()} */ public static ResolvedJavaMethod getBridgedMethod(ResolvedJavaMethod bridge) { assert bridge.isBridge(); Bytecode code = new ResolvedJavaMethodBytecode(bridge); BytecodeStream stream = new BytecodeStream(code.getCode()); int opcode = stream.currentBC(); ResolvedJavaMethod bridged = null; while (opcode != Bytecodes.END) { switch (opcode) { case INVOKEVIRTUAL: case INVOKESPECIAL: case INVOKESTATIC: case INVOKEINTERFACE: { int cpi = stream.readCPI(); ConstantPool cp = code.getConstantPool(); cp.loadReferencedType(cpi, opcode); ResolvedJavaMethod method = (ResolvedJavaMethod) cp.lookupMethod(cpi, opcode); if (method.getName().equals(bridge.getName())) { if (!assertionsEnabled()) { return method; } assert bridged == null || bridged.equals(method) : String.format( "Found calls to different methods named %s in bridge method %s%n callee 1: %s%n callee 2: %s", bridge.getName(), bridge.format("%R %H.%n(%P)"), bridged.format("%R %H.%n(%P)"), method.format("%R %H.%n(%P)")); bridged = method; } break; } } stream.next(); opcode = stream.currentBC(); } if (bridged == null) { throw new InternalError("Couldn't find method bridged by " + bridge.format("%R %H.%n(%P)")); } return bridged; }
static ResolvedJavaMethod findMethod( ResolvedJavaType type, String name, String descriptor, boolean isStatic) { if (isStatic && name.equals("<clinit>")) { ResolvedJavaMethod method = type.getClassInitializer(); if (method != null) { return method; } } ResolvedJavaMethod[] methodsToSearch = name.equals("<init>") ? type.getDeclaredConstructors() : type.getDeclaredMethods(); for (ResolvedJavaMethod method : methodsToSearch) { if (method.isStatic() == isStatic && method.getName().equals(name) && method.getSignature().toMethodDescriptor().equals(descriptor)) { return method; } } return null; }
@Override public Bytecode getBytecode(ResolvedJavaMethod method) { Classfile classfile = getClassfile(resolveToClass(method.getDeclaringClass().getName())); return classfile.getCode(method.getName(), method.getSignature().toMethodDescriptor()); }