1 /*
2  * Copyright (C) 2006 Google Inc.
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.inject.internal;
18 
19 import static com.google.inject.matcher.Matchers.annotatedWith;
20 import static com.google.inject.matcher.Matchers.any;
21 import static com.google.inject.matcher.Matchers.not;
22 import static com.google.inject.matcher.Matchers.only;
23 
24 import com.google.common.collect.Lists;
25 import com.google.inject.Inject;
26 import com.google.inject.spi.InjectionPoint;
27 import java.lang.annotation.Retention;
28 import java.lang.annotation.RetentionPolicy;
29 import java.lang.reflect.InvocationTargetException;
30 import java.util.List;
31 import junit.framework.TestCase;
32 import org.aopalliance.intercept.MethodInterceptor;
33 import org.aopalliance.intercept.MethodInvocation;
34 
35 /** @author crazybob@google.com (Bob Lee) */
36 public class ProxyFactoryTest extends TestCase {
37 
38   List<MethodAspect> aspects = Lists.newArrayList();
39 
testSimpleCase()40   public void testSimpleCase()
41       throws NoSuchMethodException, InvocationTargetException, ErrorsException {
42     SimpleInterceptor interceptor = new SimpleInterceptor();
43     InjectionPoint injectionPoint = InjectionPoint.forConstructorOf(Simple.class);
44 
45     aspects.add(new MethodAspect(any(), any(), interceptor));
46     ProxyFactory<Simple> factory = new ProxyFactory<>(injectionPoint, aspects);
47 
48     ConstructionProxy<Simple> constructionProxy = factory.create();
49 
50     Simple simple = constructionProxy.newInstance();
51     simple.invoke();
52     assertTrue(simple.invoked);
53     assertTrue(interceptor.invoked);
54   }
55 
56   static class Simple {
57     boolean invoked = false;
58 
invoke()59     public void invoke() {
60       invoked = true;
61     }
62   }
63 
64   static class SimpleInterceptor implements MethodInterceptor {
65 
66     boolean invoked = false;
67 
68     @Override
invoke(MethodInvocation methodInvocation)69     public Object invoke(MethodInvocation methodInvocation) throws Throwable {
70       invoked = true;
71       return methodInvocation.proceed();
72     }
73   }
74 
testInterceptOneMethod()75   public void testInterceptOneMethod()
76       throws NoSuchMethodException, InvocationTargetException, ErrorsException {
77     SimpleInterceptor interceptor = new SimpleInterceptor();
78 
79     aspects.add(new MethodAspect(only(Bar.class), annotatedWith(Intercept.class), interceptor));
80 
81     ConstructionProxy<Foo> fooFactory =
82         new ProxyFactory<Foo>(InjectionPoint.forConstructorOf(Foo.class), aspects).create();
83     ConstructionProxy<Bar> barFactory =
84         new ProxyFactory<Bar>(InjectionPoint.forConstructorOf(Bar.class), aspects).create();
85 
86     Foo foo = fooFactory.newInstance();
87     Bar bar = barFactory.newInstance();
88 
89     foo.foo();
90     assertTrue(foo.fooCalled);
91     assertFalse(interceptor.invoked);
92 
93     bar.bar();
94     assertTrue(bar.barCalled);
95     assertFalse(interceptor.invoked);
96 
97     bar.intercepted();
98     assertTrue(bar.interceptedCalled);
99     assertTrue(interceptor.invoked);
100   }
101 
102   static class Foo {
103     boolean fooCalled;
104 
105     @Intercept
foo()106     void foo() {
107       fooCalled = true;
108     }
109   }
110 
111   static class Bar {
112 
113     boolean barCalled;
114 
bar()115     void bar() {
116       barCalled = true;
117     }
118 
119     boolean interceptedCalled;
120 
121     @Intercept
intercepted()122     void intercepted() {
123       interceptedCalled = true;
124     }
125   }
126 
127   @Retention(RetentionPolicy.RUNTIME)
128   @interface Intercept {}
129 
testWithConstructorArguments()130   public void testWithConstructorArguments()
131       throws InvocationTargetException, NoSuchMethodException, ErrorsException {
132     SimpleInterceptor interceptor = new SimpleInterceptor();
133 
134     aspects.add(new MethodAspect(any(), any(), interceptor));
135     ProxyFactory<A> factory =
136         new ProxyFactory<A>(InjectionPoint.forConstructorOf(A.class), aspects);
137 
138     ConstructionProxy<A> constructor = factory.create();
139 
140     A a = constructor.newInstance(5);
141     a.a();
142     assertEquals(5, a.i);
143   }
144 
testNotProxied()145   public void testNotProxied()
146       throws NoSuchMethodException, InvocationTargetException, ErrorsException {
147     SimpleInterceptor interceptor = new SimpleInterceptor();
148 
149     aspects.add(new MethodAspect(not(any()), not(any()), interceptor));
150     ProxyFactory<A> factory =
151         new ProxyFactory<A>(InjectionPoint.forConstructorOf(A.class), aspects);
152 
153     ConstructionProxy<A> constructor = factory.create();
154 
155     A a = constructor.newInstance(5);
156     assertEquals(A.class, a.getClass());
157   }
158 
159   static class A {
160     final int i;
161 
162     @Inject
A(int i)163     public A(int i) {
164       this.i = i;
165     }
166 
a()167     public void a() {}
168   }
169 
testMultipleInterceptors()170   public void testMultipleInterceptors()
171       throws NoSuchMethodException, InvocationTargetException, ErrorsException {
172     DoubleInterceptor doubleInterceptor = new DoubleInterceptor();
173     CountingInterceptor countingInterceptor = new CountingInterceptor();
174 
175     aspects.add(new MethodAspect(any(), any(), doubleInterceptor, countingInterceptor));
176     ProxyFactory<Counter> factory =
177         new ProxyFactory<Counter>(InjectionPoint.forConstructorOf(Counter.class), aspects);
178 
179     ConstructionProxy<Counter> constructor = factory.create();
180 
181     Counter counter = constructor.newInstance();
182     counter.inc();
183     assertEquals(2, counter.count);
184     assertEquals(2, countingInterceptor.count);
185   }
186 
187   static class CountingInterceptor implements MethodInterceptor {
188 
189     int count;
190 
191     @Override
invoke(MethodInvocation methodInvocation)192     public Object invoke(MethodInvocation methodInvocation) throws Throwable {
193       count++;
194       return methodInvocation.proceed();
195     }
196   }
197 
198   static class DoubleInterceptor implements MethodInterceptor {
199 
200     @Override
invoke(MethodInvocation methodInvocation)201     public Object invoke(MethodInvocation methodInvocation) throws Throwable {
202       methodInvocation.proceed();
203       return methodInvocation.proceed();
204     }
205   }
206 
207   static class Counter {
208     int count;
209 
inc()210     void inc() {
211       count++;
212     }
213   }
214 }
215