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.reflect;
18 
19 import static com.google.common.base.Preconditions.checkNotNull;
20 
21 import com.google.common.collect.ImmutableList;
22 import com.google.common.testing.EqualsTester;
23 import com.google.common.testing.SerializableTester;
24 import java.io.Serializable;
25 import java.lang.reflect.Method;
26 import java.lang.reflect.Proxy;
27 import java.util.List;
28 import junit.framework.TestCase;
29 
30 /**
31  * Tests for {@link AbstractInvocationHandler}.
32  *
33  * @author Ben Yu
34  */
35 public class AbstractInvocationHandlerTest extends TestCase {
36 
37   private static final ImmutableList<String> LIST1 = ImmutableList.of("one", "two");
38   private static final ImmutableList<String> LIST2 = ImmutableList.of("three");
39 
testDelegate()40   public void testDelegate() {
41     assertEquals(LIST1, ImmutableList.copyOf(newDelegatingList(LIST1)));
42     assertEquals(LIST1, ImmutableList.copyOf(newDelegatingListWithEquals(LIST1)));
43   }
44 
testToString()45   public void testToString() {
46     List<String> proxy = newDelegatingList(LIST1);
47     assertEquals(Proxy.getInvocationHandler(proxy).toString(), proxy.toString());
48   }
49 
50   interface A {}
51 
52   interface B {}
53 
testEquals()54   public void testEquals() {
55     class AB implements A, B {}
56     class BA implements B, A {}
57     AB ab = new AB();
58     BA ba = new BA();
59     new EqualsTester()
60         .addEqualityGroup(newDelegatingList(LIST1))
61         // Actually, this violates List#equals contract.
62         // But whatever, no one is going to proxy List (hopefully).
63         .addEqualityGroup(newDelegatingList(LIST1))
64         .addEqualityGroup(newDelegatingList(LIST2))
65         .addEqualityGroup(
66             newProxyWithEqualsForInterfaces(List.class, Runnable.class),
67             newProxyWithEqualsForInterfaces(List.class, Runnable.class))
68         .addEqualityGroup(newProxyWithEqualsForInterfaces(Runnable.class, List.class))
69         .addEqualityGroup(
70             newDelegatingListWithEquals(LIST1),
71             newDelegatingListWithEquals(LIST1),
72             SerializableTester.reserialize(newDelegatingListWithEquals(LIST1)))
73         .addEqualityGroup(
74             newDelegatingListWithEquals(LIST2),
75             newProxyWithSubHandler1(LIST2), // Makes sure type of handler doesn't affect equality
76             newProxyWithSubHandler2(LIST2))
77         .addEqualityGroup(newDelegatingIterableWithEquals(LIST2)) // different interface
78         .testEquals();
79   }
80 
81   @SuppressWarnings("unchecked") // proxy of List<String>
newDelegatingList(List<String> delegate)82   private static List<String> newDelegatingList(List<String> delegate) {
83     return Reflection.newProxy(List.class, new DelegatingInvocationHandler(delegate));
84   }
85 
86   @SuppressWarnings("unchecked") // proxy of List<String>
newDelegatingListWithEquals(List<String> delegate)87   private static List<String> newDelegatingListWithEquals(List<String> delegate) {
88     return Reflection.newProxy(List.class, new DelegatingInvocationHandlerWithEquals(delegate));
89   }
90 
91   @SuppressWarnings("unchecked") // proxy of Iterable<String>
newDelegatingIterableWithEquals(Iterable<String> delegate)92   private static Iterable<String> newDelegatingIterableWithEquals(Iterable<String> delegate) {
93     return Reflection.newProxy(Iterable.class, new DelegatingInvocationHandlerWithEquals(delegate));
94   }
95 
96   @SuppressWarnings("unchecked") // proxy of List<String>
newProxyWithSubHandler1(List<String> delegate)97   private static List<String> newProxyWithSubHandler1(List<String> delegate) {
98     return Reflection.newProxy(List.class, new SubHandler1(delegate));
99   }
100 
101   @SuppressWarnings("unchecked") // proxy of List<String>
newProxyWithSubHandler2(List<String> delegate)102   private static List<String> newProxyWithSubHandler2(List<String> delegate) {
103     return Reflection.newProxy(List.class, new SubHandler2(delegate));
104   }
105 
newProxyWithEqualsForInterfaces(Class<?>.... interfaces)106   private static Object newProxyWithEqualsForInterfaces(Class<?>... interfaces) {
107     return Proxy.newProxyInstance(
108         AbstractInvocationHandlerTest.class.getClassLoader(),
109         interfaces,
110         new DelegatingInvocationHandlerWithEquals("a string"));
111   }
112 
113   private static class DelegatingInvocationHandler extends AbstractInvocationHandler
114       implements Serializable {
115     final Object delegate;
116 
DelegatingInvocationHandler(Object delegate)117     DelegatingInvocationHandler(Object delegate) {
118       this.delegate = checkNotNull(delegate);
119     }
120 
121     @Override
handleInvocation(Object proxy, Method method, Object[] args)122     protected Object handleInvocation(Object proxy, Method method, Object[] args) throws Throwable {
123       return method.invoke(delegate, args);
124     }
125 
126     @Override
toString()127     public String toString() {
128       return "some arbitrary string";
129     }
130   }
131 
132   private static class DelegatingInvocationHandlerWithEquals extends DelegatingInvocationHandler {
133 
DelegatingInvocationHandlerWithEquals(Object delegate)134     DelegatingInvocationHandlerWithEquals(Object delegate) {
135       super(delegate);
136     }
137 
138     @Override
equals(Object obj)139     public boolean equals(Object obj) {
140       if (obj instanceof DelegatingInvocationHandlerWithEquals) {
141         DelegatingInvocationHandlerWithEquals that = (DelegatingInvocationHandlerWithEquals) obj;
142         return delegate.equals(that.delegate);
143       } else {
144         return false;
145       }
146     }
147 
148     @Override
hashCode()149     public int hashCode() {
150       return delegate.hashCode();
151     }
152 
153     @Override
toString()154     public String toString() {
155       return "another arbitrary string";
156     }
157   }
158 
159   private static class SubHandler1 extends DelegatingInvocationHandlerWithEquals {
SubHandler1(Object delegate)160     SubHandler1(Object delegate) {
161       super(delegate);
162     }
163   }
164 
165   private static class SubHandler2 extends DelegatingInvocationHandlerWithEquals {
SubHandler2(Object delegate)166     SubHandler2(Object delegate) {
167       super(delegate);
168     }
169   }
170 }
171