• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 com.google.inject.internal.InjectorImpl.InjectorOptions;
20 import java.lang.reflect.Proxy;
21 import java.util.ArrayList;
22 import java.util.List;
23 
24 /**
25  * Context of a dependency construction. Used to manage circular references.
26  *
27  * @author crazybob@google.com (Bob Lee)
28  */
29 final class ConstructionContext<T> {
30 
31   T currentReference;
32   boolean constructing;
33 
34   List<DelegatingInvocationHandler<T>> invocationHandlers;
35 
getCurrentReference()36   public T getCurrentReference() {
37     return currentReference;
38   }
39 
removeCurrentReference()40   public void removeCurrentReference() {
41     this.currentReference = null;
42   }
43 
setCurrentReference(T currentReference)44   public void setCurrentReference(T currentReference) {
45     this.currentReference = currentReference;
46   }
47 
isConstructing()48   public boolean isConstructing() {
49     return constructing;
50   }
51 
startConstruction()52   public void startConstruction() {
53     this.constructing = true;
54   }
55 
finishConstruction()56   public void finishConstruction() {
57     this.constructing = false;
58     invocationHandlers = null;
59   }
60 
createProxy(InjectorOptions injectorOptions, Class<?> expectedType)61   public Object createProxy(InjectorOptions injectorOptions, Class<?> expectedType)
62       throws InternalProvisionException {
63     if (injectorOptions.disableCircularProxies) {
64       throw InternalProvisionException.circularDependenciesDisabled(expectedType);
65     }
66     if (!expectedType.isInterface()) {
67       throw InternalProvisionException.cannotProxyClass(expectedType);
68     }
69 
70     if (invocationHandlers == null) {
71       invocationHandlers = new ArrayList<>();
72     }
73 
74     DelegatingInvocationHandler<T> invocationHandler = new DelegatingInvocationHandler<>();
75     invocationHandlers.add(invocationHandler);
76 
77     // TODO: if I create a proxy which implements all the interfaces of
78     // the implementation type, I'll be able to get away with one proxy
79     // instance (as opposed to one per caller).
80     ClassLoader classLoader = BytecodeGen.getClassLoader(expectedType);
81     return expectedType.cast(
82         Proxy.newProxyInstance(
83             classLoader,
84             new Class[] {expectedType, CircularDependencyProxy.class},
85             invocationHandler));
86   }
87 
setProxyDelegates(T delegate)88   public void setProxyDelegates(T delegate) {
89     if (invocationHandlers != null) {
90       for (DelegatingInvocationHandler<T> handler : invocationHandlers) {
91         handler.setDelegate(delegate);
92       }
93       // initialization of each handler can happen no more than once
94       invocationHandlers = null;
95     }
96   }
97 }
98