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