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