1 /*
2  * Copyright (C) 2012 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.dx.mockito;
18 
19 import com.android.dx.stock.ProxyBuilder;
20 import org.mockito.internal.debugging.LocationImpl;
21 import org.mockito.internal.invocation.InvocationImpl;
22 import org.mockito.internal.invocation.MockitoMethod;
23 import org.mockito.internal.invocation.realmethod.RealMethod;
24 import org.mockito.internal.progress.SequenceNumber;
25 import org.mockito.invocation.MockHandler;
26 
27 import java.lang.reflect.InvocationHandler;
28 import java.lang.reflect.Method;
29 import java.lang.reflect.Modifier;
30 
31 /**
32  * Handles proxy method invocations to dexmaker's InvocationHandler by calling
33  * a MockitoInvocationHandler.
34  */
35 final class InvocationHandlerAdapter implements InvocationHandler {
36     private MockHandler handler;
37 
InvocationHandlerAdapter(MockHandler handler)38     public InvocationHandlerAdapter(MockHandler handler) {
39         this.handler = handler;
40     }
41 
42     @Override
invoke(Object proxy, Method method, Object[] args)43     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
44         // args can be null if the method invoked has no arguments, but Mockito expects a non-null array
45         args = args != null ? args : new Object[0];
46         if (isEqualsMethod(method)) {
47             return proxy == args[0];
48         } else if (isHashCodeMethod(method)) {
49             return System.identityHashCode(proxy);
50         }
51 
52         ProxiedMethod proxiedMethod = new ProxiedMethod(method);
53         return handler.handle(new InvocationImpl(proxy, proxiedMethod, args, SequenceNumber.next(),
54                 proxiedMethod, new LocationImpl()));
55     }
56 
getHandler()57     public MockHandler getHandler() {
58         return handler;
59     }
60 
setHandler(MockHandler handler)61     public void setHandler(MockHandler handler) {
62         this.handler = handler;
63     }
64 
isEqualsMethod(Method method)65     private static boolean isEqualsMethod(Method method) {
66         return method.getName().equals("equals")
67                 && method.getParameterTypes().length == 1
68                 && method.getParameterTypes()[0] == Object.class;
69     }
70 
isHashCodeMethod(Method method)71     private static boolean isHashCodeMethod(Method method) {
72         return method.getName().equals("hashCode")
73                 && method.getParameterTypes().length == 0;
74     }
75 
76     private static class ProxiedMethod implements MockitoMethod, RealMethod {
77         private final Method method;
78 
ProxiedMethod(Method method)79         ProxiedMethod(Method method) {
80             this.method = method;
81         }
82 
83         @Override
getName()84         public String getName() {
85             return method.getName();
86         }
87 
88         @Override
getReturnType()89         public Class<?> getReturnType() {
90             return method.getReturnType();
91         }
92 
93         @Override
getParameterTypes()94         public Class<?>[] getParameterTypes() {
95             return method.getParameterTypes();
96         }
97 
98         @Override
getExceptionTypes()99         public Class<?>[] getExceptionTypes() {
100             return method.getExceptionTypes();
101         }
102 
103         @Override
isVarArgs()104         public boolean isVarArgs() {
105             return method.isVarArgs();
106         }
107 
108         @Override
getJavaMethod()109         public Method getJavaMethod() {
110             return method;
111         }
112 
113         @Override
invoke(Object target, Object[] arguments)114         public Object invoke(Object target, Object[] arguments) throws Throwable {
115             return ProxyBuilder.callSuper(target, method, arguments);
116         }
117 
118         @Override
isAbstract()119         public boolean isAbstract() {
120             return Modifier.isAbstract(method.getModifiers());
121         }
122     }
123 }
124