/* * Copyright (c) 2007 Mockito contributors * This program is made available under the terms of the MIT License. */ package org.mockito.internal.stubbing.defaultanswers; import static org.mockito.internal.exceptions.Reporter.delegatedMethodDoesNotExistOnDelegate; import static org.mockito.internal.exceptions.Reporter.delegatedMethodHasWrongReturnType; import java.io.Serializable; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import org.mockito.invocation.Invocation; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; /** * Internal answer to forward invocations on a real instance. * * @since 1.9.5 */ public class ForwardsInvocations implements Answer<Object>, Serializable { private static final long serialVersionUID = -8343690268123254910L; private Object delegatedObject = null ; public ForwardsInvocations(Object delegatedObject) { this.delegatedObject = delegatedObject ; } public Object answer(InvocationOnMock invocation) throws Throwable { Method mockMethod = invocation.getMethod(); try { Method delegateMethod = getDelegateMethod(mockMethod); if (!compatibleReturnTypes(mockMethod.getReturnType(), delegateMethod.getReturnType())) { throw delegatedMethodHasWrongReturnType(mockMethod, delegateMethod, invocation.getMock(), delegatedObject); } Object[] rawArguments = ((Invocation) invocation).getRawArguments(); return delegateMethod.invoke(delegatedObject, rawArguments); } catch (NoSuchMethodException e) { throw delegatedMethodDoesNotExistOnDelegate(mockMethod, invocation.getMock(), delegatedObject); } catch (InvocationTargetException e) { // propagate the original exception from the delegate throw e.getCause(); } } private Method getDelegateMethod(Method mockMethod) throws NoSuchMethodException { if (mockMethod.getDeclaringClass().isAssignableFrom(delegatedObject.getClass())) { // Compatible class. Return original method. return mockMethod; } else { // Return method of delegate object with the same signature as mockMethod. return delegatedObject.getClass().getMethod(mockMethod.getName(), mockMethod.getParameterTypes()); } } private static boolean compatibleReturnTypes(Class<?> superType, Class<?> subType) { return superType.equals(subType) || superType.isAssignableFrom(subType); } }