• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (C) 2014 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.jdk8;
18 
19 import static java.lang.annotation.ElementType.METHOD;
20 import static java.lang.annotation.ElementType.TYPE;
21 import static java.lang.annotation.RetentionPolicy.RUNTIME;
22 
23 import com.google.inject.AbstractModule;
24 import com.google.inject.Guice;
25 import com.google.inject.Injector;
26 import com.google.inject.matcher.Matchers;
27 
28 import junit.framework.TestCase;
29 
30 import org.aopalliance.intercept.MethodInterceptor;
31 
32 import java.lang.annotation.Retention;
33 import java.lang.annotation.Target;
34 import java.util.concurrent.atomic.AtomicInteger;
35 
36 /**
37  * Tests for interception of default methods.
38  *
39  * @author cgdecker@google.com (Colin Decker)
40  */
41 public class DefaultMethodInterceptionTest extends TestCase {
42 
43   private static final AtomicInteger callCount = new AtomicInteger(0);
44   private static final AtomicInteger interceptedCallCount = new AtomicInteger(0);
45 
46   // the interceptor's a lambda too
47   private final MethodInterceptor interceptor = invocation -> {
48     interceptedCallCount.incrementAndGet();
49     return invocation.proceed();
50   };
51 
52   @Override
setUp()53   protected void setUp() throws Exception {
54     callCount.set(0);
55     interceptedCallCount.set(0);
56   }
57 
58   @Retention(RUNTIME)
59   @Target({METHOD, TYPE})
60   public @interface InterceptMe {}
61 
62   /** Interface with a default method annotated to be intercepted. */
63   public interface Foo {
64     @InterceptMe
defaultMethod()65     default String defaultMethod() {
66       callCount.incrementAndGet();
67       return "Foo";
68     }
69   }
70 
71   /** Foo implementation that does not override the default method. */
72   public static class NonOverridingFoo implements Foo {
methodCallingDefault()73     public String methodCallingDefault() {
74       return "NonOverriding-" + defaultMethod();
75     }
76   }
77 
testInterceptedDefaultMethod()78   public void testInterceptedDefaultMethod() {
79     Injector injector = Guice.createInjector(new AbstractModule() {
80       @Override
81       protected void configure() {
82         bindInterceptor(Matchers.any(), Matchers.annotatedWith(InterceptMe.class),
83             interceptor);
84         bind(Foo.class).to(NonOverridingFoo.class);
85       }
86     });
87 
88     Foo foo = injector.getInstance(Foo.class);
89     assertEquals("Foo", foo.defaultMethod());
90     assertEquals(1, callCount.get());
91     assertEquals(1, interceptedCallCount.get());
92   }
93 
testInterceptedDefaultMethod_calledByAnotherMethod()94   public void testInterceptedDefaultMethod_calledByAnotherMethod() {
95     Injector injector = Guice.createInjector(new AbstractModule() {
96       @Override
97       protected void configure() {
98         bindInterceptor(Matchers.any(), Matchers.annotatedWith(InterceptMe.class),
99             interceptor);
100       }
101     });
102 
103     NonOverridingFoo foo = injector.getInstance(NonOverridingFoo.class);
104     assertEquals("NonOverriding-Foo", foo.methodCallingDefault());
105     assertEquals(1, callCount.get());
106     assertEquals(1, interceptedCallCount.get());
107   }
108 
109   /** A base class defining a method with the same signature as Foo's default method. */
110   public static class BaseClass {
111     // the definition of this method on the class will win over the default method
defaultMethod()112     public String defaultMethod() {
113       callCount.incrementAndGet();
114       return "BaseClass";
115     }
116   }
117 
118   /** Foo implementation that should use superclass method rather than default method. */
119   public static class InheritingFoo extends BaseClass implements Foo {
120   }
121 
testInterceptedDefaultMethod_whenParentClassDefinesNonInterceptedMethod()122   public void testInterceptedDefaultMethod_whenParentClassDefinesNonInterceptedMethod() {
123     Injector injector = Guice.createInjector(new AbstractModule() {
124       @Override
125       protected void configure() {
126         bindInterceptor(Matchers.any(), Matchers.annotatedWith(InterceptMe.class),
127             interceptor);
128         bind(Foo.class).to(InheritingFoo.class);
129       }
130     });
131 
132     // the concrete implementation that wins is not annotated
133     Foo foo = injector.getInstance(Foo.class);
134     assertEquals("BaseClass", foo.defaultMethod());
135     assertEquals(1, callCount.get());
136     assertEquals(0, interceptedCallCount.get());
137   }
138 
139   /**
140    * A base class defining an intercepted method with the same signature as Foo's default method.
141    */
142   public static class BaseClass2 {
143     // the definition of this method on the class will win over the default method
144     @InterceptMe
defaultMethod()145     public String defaultMethod() {
146       callCount.incrementAndGet();
147       return "BaseClass2";
148     }
149   }
150 
151   /**
152    * Foo implementation that should use intercepted superclass method rather than default method.
153    */
154   public static class InheritingFoo2 extends BaseClass2 implements Foo {
155   }
156 
testInterceptedDefaultMethod_whenParentClassDefinesInterceptedMethod()157   public void testInterceptedDefaultMethod_whenParentClassDefinesInterceptedMethod() {
158     Injector injector = Guice.createInjector(new AbstractModule() {
159       @Override
160       protected void configure() {
161         bindInterceptor(Matchers.any(), Matchers.annotatedWith(InterceptMe.class),
162             interceptor);
163         bind(Foo.class).to(InheritingFoo2.class);
164       }
165     });
166 
167     // the concrete implementation that wins is not annotated
168     Foo foo = injector.getInstance(Foo.class);
169     assertEquals("BaseClass2", foo.defaultMethod());
170     assertEquals(1, callCount.get());
171     assertEquals(1, interceptedCallCount.get());
172   }
173 
174   public interface Baz {
doSomething()175     default String doSomething() {
176       return "Baz";
177     }
178 
doSomethingElse()179     String doSomethingElse();
180   }
181 
182   public static class BazImpl implements Baz {
183 
184     @Override
doSomethingElse()185     public String doSomethingElse() {
186       return "BazImpl";
187     }
188   }
189 
testInterception_ofAllMethodsOnType()190   public void testInterception_ofAllMethodsOnType() {
191     Injector injector = Guice.createInjector(new AbstractModule() {
192       @Override
193       protected void configure() {
194         bindInterceptor(Matchers.subclassesOf(Baz.class), Matchers.any(), interceptor);
195         bind(Baz.class).to(BazImpl.class);
196       }
197     });
198 
199     Baz baz = injector.getInstance(Baz.class);
200 
201     assertEquals("Baz", baz.doSomething());
202     assertEquals("BazImpl", baz.doSomethingElse());
203 
204     assertEquals(2, interceptedCallCount.get());
205   }
206 
testInterception_ofAllMethodsOnType_interceptsInheritedDefaultMethod()207   public void testInterception_ofAllMethodsOnType_interceptsInheritedDefaultMethod() {
208     Injector injector = Guice.createInjector(new AbstractModule() {
209       @Override
210       protected void configure() {
211         bindInterceptor(Matchers.subclassesOf(BazImpl.class), Matchers.any(), interceptor);
212         bind(Baz.class).to(BazImpl.class);
213       }
214     });
215 
216     Baz baz = injector.getInstance(Baz.class);
217 
218     assertEquals("Baz", baz.doSomething());
219     assertEquals("BazImpl", baz.doSomethingElse());
220 
221     assertEquals(2, interceptedCallCount.get());
222   }
223 }
224