• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 The Guava Authors
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.google.common.testing;
18 
19 import static com.google.common.base.Preconditions.checkNotNull;
20 import static com.google.common.testing.NullPointerTester.isNullable;
21 
22 import com.google.common.annotations.GwtIncompatible;
23 import com.google.common.collect.ImmutableList;
24 import com.google.common.collect.Sets;
25 import com.google.common.reflect.AbstractInvocationHandler;
26 import com.google.common.reflect.Invokable;
27 import com.google.common.reflect.Parameter;
28 import com.google.common.reflect.TypeToken;
29 import java.io.Serializable;
30 import java.lang.reflect.Method;
31 import java.lang.reflect.Proxy;
32 import java.util.Set;
33 
34 /**
35  * Generates a dummy interface proxy that simply returns a dummy value for each method.
36  *
37  * @author Ben Yu
38  */
39 @GwtIncompatible
40 abstract class DummyProxy {
41 
42   /**
43    * Returns a new proxy for {@code interfaceType}. Proxies of the same interface are equal to each
44    * other if the {@link DummyProxy} instance that created the proxies are equal.
45    */
newProxy(TypeToken<T> interfaceType)46   final <T> T newProxy(TypeToken<T> interfaceType) {
47     Set<Class<?>> interfaceClasses = Sets.newLinkedHashSet();
48     interfaceClasses.addAll(interfaceType.getTypes().interfaces().rawTypes());
49     // Make the proxy serializable to work with SerializableTester
50     interfaceClasses.add(Serializable.class);
51     Object dummy =
52         Proxy.newProxyInstance(
53             interfaceClasses.iterator().next().getClassLoader(),
54             interfaceClasses.toArray(new Class<?>[interfaceClasses.size()]),
55             new DummyHandler(interfaceType));
56     @SuppressWarnings("unchecked") // interfaceType is T
57     T result = (T) dummy;
58     return result;
59   }
60 
61   /** Returns the dummy return value for {@code returnType}. */
dummyReturnValue(TypeToken<R> returnType)62   abstract <R> R dummyReturnValue(TypeToken<R> returnType);
63 
64   private class DummyHandler extends AbstractInvocationHandler implements Serializable {
65     private final TypeToken<?> interfaceType;
66 
DummyHandler(TypeToken<?> interfaceType)67     DummyHandler(TypeToken<?> interfaceType) {
68       this.interfaceType = interfaceType;
69     }
70 
71     @Override
handleInvocation(Object proxy, Method method, Object[] args)72     protected Object handleInvocation(Object proxy, Method method, Object[] args) {
73       Invokable<?, ?> invokable = interfaceType.method(method);
74       ImmutableList<Parameter> params = invokable.getParameters();
75       for (int i = 0; i < args.length; i++) {
76         Parameter param = params.get(i);
77         if (!isNullable(param)) {
78           checkNotNull(args[i]);
79         }
80       }
81       return dummyReturnValue(interfaceType.resolveType(method.getGenericReturnType()));
82     }
83 
84     @Override
hashCode()85     public int hashCode() {
86       return identity().hashCode();
87     }
88 
89     @Override
equals(Object obj)90     public boolean equals(Object obj) {
91       if (obj instanceof DummyHandler) {
92         DummyHandler that = (DummyHandler) obj;
93         return identity().equals(that.identity());
94       } else {
95         return false;
96       }
97     }
98 
identity()99     private DummyProxy identity() {
100       return DummyProxy.this;
101     }
102 
103     @Override
toString()104     public String toString() {
105       return "Dummy proxy for " + interfaceType;
106     }
107 
108     // Since type variables aren't serializable, reduce the type down to raw type before
109     // serialization.
writeReplace()110     private Object writeReplace() {
111       return new DummyHandler(TypeToken.of(interfaceType.getRawType()));
112     }
113   }
114 }
115