private MethodVisitor generateCallToHandlerThroughMockingBridge( int access, String name, String desc, String genericSignature, String[] exceptions, String internalClassName, int executionMode) { generateCodeToObtainInstanceOfMockingBridge(MockedBridge.class.getName()); // First and second "invoke" arguments: boolean isStatic = generateCodeToPassThisOrNullIfStaticMethod(access); mw.visitInsn(ACONST_NULL); // Create array for call arguments (third "invoke" argument): Type[] argTypes = Type.getArgumentTypes(desc); generateCodeToCreateArrayOfObject(7 + argTypes.length); int i = 0; generateCodeToFillArrayElement(i++, access); generateCodeToFillArrayElement(i++, internalClassName); generateCodeToFillArrayElement(i++, name); generateCodeToFillArrayElement(i++, desc); generateCodeToFillArrayElement(i++, genericSignature); generateCodeToFillArrayElement(i++, getListOfExceptionsAsSingleString(exceptions)); generateCodeToFillArrayElement(i++, executionMode); generateCodeToPassMethodArgumentsAsVarargs(argTypes, i, isStatic ? 0 : 1); generateCallToInvocationHandler(); generateDecisionBetweenReturningOrContinuingToRealImplementation(desc); // Copies the entire original implementation even for a constructor, in which case the complete // bytecode inside // the constructor fails the strict verification activated by "-Xfuture". However, this is // necessary to allow the // full execution of a JRE constructor when the call was not meant to be mocked. return copyOriginalImplementationCode(access, desc); }
@Override public MethodVisitor visitMethod( int access, String name, String desc, String signature, String[] exceptions) { boolean syntheticOrAbstractMethod = (access & METHOD_ACCESS_MASK) != 0; if (syntheticOrAbstractMethod || isProxy && isConstructorOrSystemMethodNotToBeMocked(name, desc)) { return unmodifiedBytecode(access, name, desc, signature, exceptions); } boolean noFiltersToMatch = mockingCfg == null; boolean matchesFilters = noFiltersToMatch || mockingCfg.matchesFilters(name, desc); if ("<clinit>".equals(name)) { return stubOutClassInitializationIfApplicable(access, noFiltersToMatch, matchesFilters); } else if (stubOutFinalizeMethod(access, name, desc)) { return null; } if (!matchesFilters || isMethodFromCapturedClassNotToBeMocked(access) || noFiltersToMatch && isMethodOrConstructorNotToBeMocked(access, name)) { return unmodifiedBytecode(access, name, desc, signature, exceptions); } // Otherwise, replace original implementation with redirect to JMockit. validateModificationOfNativeMethod(access, name); startModifiedMethodVersion(access, name, desc, signature, exceptions); boolean visitingConstructor = "<init>".equals(name); if (visitingConstructor && superClassName != null) { generateCallToSuperConstructor(); } String internalClassName = className; if (!visitingConstructor && baseClassNameForCapturedInstanceMethods != null) { internalClassName = baseClassNameForCapturedInstanceMethods; } int actualExecutionMode = determineAppropriateExecutionMode(access, visitingConstructor); if (useMockingBridge) { return generateCallToHandlerThroughMockingBridge( access, name, desc, signature, exceptions, internalClassName, actualExecutionMode); } generateDirectCallToHandler( internalClassName, access, name, desc, signature, exceptions, actualExecutionMode); if (actualExecutionMode > 0) { generateDecisionBetweenReturningOrContinuingToRealImplementation(desc); // Constructors of non-JRE classes can't be modified (unless running with "-noverify") in a // way that // "super(...)/this(...)" get called twice, so we disregard such calls when copying the // original bytecode. return visitingConstructor ? new DynamicConstructorModifier() : copyOriginalImplementationCode(access, desc); } generateReturnWithObjectAtTopOfTheStack(desc); mw.visitMaxs(1, 0); return methodAnnotationsVisitor; }