/** * Creates a method handle representation of the given method. * * @param methodDescription The method ro represent. * @return A method handle representing the given method. */ public static MethodHandle of(MethodDescription methodDescription) { return new MethodHandle( HandleType.of(methodDescription), methodDescription.getDeclaringType().asRawType(), methodDescription.getInternalName(), methodDescription.getReturnType().asRawType(), methodDescription.getParameters().asTypeList().asRawTypes()); }
/** * Extracts a handle type for invoking the given method. * * @param methodDescription The method for which a handle type should be found. * @return The handle type for the given method. */ protected static HandleType of(MethodDescription methodDescription) { if (methodDescription.isStatic()) { return INVOKE_STATIC; } else if (methodDescription.isPrivate()) { return INVOKE_SPECIAL; } else if (methodDescription.isConstructor()) { return INVOKE_SPECIAL_CONSTRUCTOR; } else if (methodDescription.getDeclaringType().asRawType().isInterface()) { return INVOKE_INTERFACE; } else { return INVOKE_VIRTUAL; } }
@Before public void setUp() throws Exception { when(methodDescription.getDeclaringType()).thenReturn(typeDescription); when(methodDescription.getReturnType()).thenReturn(returnType); when(methodDescription.getInternalName()).thenReturn(FOO); when(methodDescription.getDescriptor()).thenReturn(BAZ); when(typeDescription.getInternalName()).thenReturn(BAR); when(typeDescription.getDescriptor()).thenReturn(BAR); when(methodNameTransformer.transform(methodDescription)).thenReturn(QUX); when(otherMethodNameTransformer.transform(methodDescription)).thenReturn(FOO + BAR); when(parameterType.getStackSize()).thenReturn(StackSize.ZERO); ParameterList parameterList = ParameterList.Explicit.latent(methodDescription, Collections.singletonList(parameterType)); when(methodDescription.getParameters()).thenReturn(parameterList); }
/** * Creates a linked hash map of field names to their types where each field represents a parameter * of the method. * * @param methodDescription The method to extract into fields. * @return A map of fields in the order they need to be loaded onto the operand stack for invoking * the original method, including a reference to the instance of the instrumented type that is * invoked if applicable. */ private static LinkedHashMap<String, TypeDescription> extractFields( MethodDescription methodDescription) { ParameterList<?> parameters = methodDescription.getParameters(); LinkedHashMap<String, TypeDescription> typeDescriptions = new LinkedHashMap<String, TypeDescription>( (methodDescription.isStatic() ? 0 : 1) + parameters.size()); int currentIndex = 0; if (!methodDescription.isStatic()) { typeDescriptions.put( fieldName(currentIndex++), methodDescription.getDeclaringType().asErasure()); } for (ParameterDescription parameterDescription : parameters) { typeDescriptions.put(fieldName(currentIndex++), parameterDescription.getType().asErasure()); } return typeDescriptions; }
@Override @Before public void setUp() throws Exception { when(parameterList.asTypeList()).thenReturn(parameterTypes); when(instrumentedType.getSupertype()).thenReturn(superType); when(superType.getDeclaredMethods()) .thenReturn(new MethodList.Explicit(Collections.singletonList(superMethodConstructor))); when(superType.getInternalName()).thenReturn(BAR); when(superMethod.getDeclaringType()).thenReturn(superType); when(superType.getStackSize()).thenReturn(StackSize.ZERO); when(superMethod.getReturnType()).thenReturn(returnType); when(superMethod.getInternalName()).thenReturn(BAZ); when(superMethod.getDescriptor()).thenReturn(FOOBAR); when(superMethod.getParameters()).thenReturn(parameterList); when(superMethodConstructor.isConstructor()).thenReturn(true); when(superMethodConstructor.getParameters()).thenReturn(parameterList); when(superMethodConstructor.getReturnType()).thenReturn(returnType); when(superMethodConstructor.isSpecializableFor(superType)).thenReturn(true); when(superMethodConstructor.getInternalName()).thenReturn(QUXBAZ); when(superMethodConstructor.getDescriptor()).thenReturn(BAZBAR); super.setUp(); }
@Override public MethodRegistry.Prepared prepare( InstrumentedType instrumentedType, MethodGraph.Compiler methodGraphCompiler, LatentMethodMatcher methodFilter) { LinkedHashMap<MethodDescription, Prepared.Entry> implementations = new LinkedHashMap<MethodDescription, Prepared.Entry>(); Set<Handler> handlers = new HashSet<Handler>(entries.size()); MethodList<?> helperMethods = instrumentedType.getDeclaredMethods(); for (Entry entry : entries) { if (handlers.add(entry.getHandler())) { instrumentedType = entry.getHandler().prepare(instrumentedType); ElementMatcher<? super MethodDescription> handledMethods = noneOf(helperMethods); helperMethods = instrumentedType.getDeclaredMethods(); for (MethodDescription helperMethod : helperMethods.filter(handledMethods)) { implementations.put(helperMethod, entry.asSupplementaryEntry(helperMethod)); } } } MethodGraph.Linked methodGraph = methodGraphCompiler.compile(instrumentedType); // Casting required for Java 6 compiler. ElementMatcher<? super MethodDescription> relevanceMatcher = (ElementMatcher<? super MethodDescription>) not(anyOf(implementations.keySet())).and(methodFilter.resolve(instrumentedType)); for (MethodGraph.Node node : methodGraph.listNodes()) { MethodDescription methodDescription = node.getRepresentative(); boolean visibilityBridge = instrumentedType.isPublic() && !instrumentedType.isInterface(); if (relevanceMatcher.matches(methodDescription)) { for (Entry entry : entries) { if (entry.resolve(instrumentedType).matches(methodDescription)) { implementations.put( methodDescription, entry.asPreparedEntry( instrumentedType, methodDescription, node.getMethodTypes())); visibilityBridge = false; break; } } } if (visibilityBridge && methodDescription.isPublic() && !(methodDescription.isAbstract() || methodDescription.isFinal()) && !node.getSort().isMadeVisible() && methodDescription.getDeclaringType().asErasure().isPackagePrivate()) { // Visibility bridges are required for public types that inherit a public method from a // package-private type. // Checking the last condition contradicts any method that is defined by the instrumented // type itself. implementations.put( methodDescription, Prepared.Entry.forVisibilityBridge(methodDescription, node.getMethodTypes())); } } MethodDescription typeInitializer = new MethodDescription.Latent.TypeInitializer(instrumentedType); for (Entry entry : entries) { if (entry.resolve(instrumentedType).matches(typeInitializer)) { implementations.put( typeInitializer, entry.asPreparedEntry( instrumentedType, typeInitializer, Collections.<MethodDescription.TypeToken>emptySet())); break; } } return new Prepared( implementations, instrumentedType.getLoadedTypeInitializer(), instrumentedType.getTypeInitializer(), instrumentedType.asErasure(), methodGraph); }