KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > google > inject > ConstructorInjector


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;
18
19 import com.google.inject.util.StackTraceElements;
20 import java.lang.reflect.Constructor JavaDoc;
21 import java.lang.reflect.InvocationTargetException JavaDoc;
22
23 /**
24  * Injects constructors.
25  *
26  * @author crazybob@google.com (Bob Lee)
27  */

28 class ConstructorInjector<T> {
29
30   final Class JavaDoc<T> implementation;
31   final InjectorImpl.SingleMemberInjector[] memberInjectors;
32   final InjectorImpl.SingleParameterInjector<?>[] parameterInjectors;
33   final ConstructionProxy<T> constructionProxy;
34
35   ConstructorInjector(InjectorImpl injector, Class JavaDoc<T> implementation) {
36     this.implementation = implementation;
37     Constructor JavaDoc<T> constructor = findConstructorIn(injector, implementation);
38     parameterInjectors = createParameterInjector(injector, constructor);
39     memberInjectors = injector.injectors.get(implementation)
40         .toArray(new InjectorImpl.SingleMemberInjector[0]);
41     constructionProxy = injector.constructionProxyFactory.get(constructor);
42   }
43
44   /**
45    * Used to create an invalid injector.
46    */

47   private ConstructorInjector() {
48     implementation = null;
49     memberInjectors = null;
50     parameterInjectors = null;
51     constructionProxy = null;
52   }
53
54   InjectorImpl.SingleParameterInjector<?>[] createParameterInjector(
55       InjectorImpl injector, Constructor JavaDoc<T> constructor) {
56     try {
57       return constructor.getParameterTypes().length == 0
58           ? null // default constructor.
59
: injector.getParametersInjectors(
60               constructor,
61               constructor.getParameterAnnotations(),
62               constructor.getGenericParameterTypes()
63           );
64     }
65     catch (InjectorImpl.MissingDependencyException e) {
66       e.handle(injector.errorHandler);
67       return null;
68     }
69   }
70
71   private Constructor JavaDoc<T> findConstructorIn(InjectorImpl injector,
72       Class JavaDoc<T> implementation) {
73     Constructor JavaDoc<T> found = null;
74     @SuppressWarnings JavaDoc("unchecked")
75     Constructor JavaDoc<T>[] constructors
76         = (Constructor JavaDoc<T>[]) implementation.getDeclaredConstructors();
77     for (Constructor JavaDoc<T> constructor : constructors) {
78       Inject inject = constructor.getAnnotation(Inject.class);
79       if (inject != null) {
80         if (inject.optional()) {
81           injector.errorHandler.handle(
82               StackTraceElements.forMember(constructor),
83               ErrorMessages.OPTIONAL_CONSTRUCTOR);
84         }
85
86         if (found != null) {
87           injector.errorHandler.handle(
88               StackTraceElements.forMember(found),
89               ErrorMessages.TOO_MANY_CONSTRUCTORS);
90           return InjectorImpl.invalidConstructor();
91         }
92         found = constructor;
93       }
94     }
95     if (found != null) {
96       return found;
97     }
98
99     // If no annotated constructor is found, look for a no-arg constructor
100
// instead.
101
try {
102       return implementation.getDeclaredConstructor();
103     }
104     catch (NoSuchMethodException JavaDoc e) {
105       injector.errorHandler.handle(
106           StackTraceElements.forMember(
107               implementation.getDeclaredConstructors()[0]),
108           ErrorMessages.MISSING_CONSTRUCTOR,
109           implementation);
110       return InjectorImpl.invalidConstructor();
111     }
112   }
113
114   /**
115    * Construct an instance. Returns {@code Object} instead of {@code T} because
116    * it may return a proxy.
117    */

118   Object JavaDoc construct(InternalContext context, Class JavaDoc<?> expectedType) {
119     ConstructionContext<T> constructionContext
120         = context.getConstructionContext(this);
121
122     // We have a circular reference between constructors. Return a proxy.
123
if (constructionContext.isConstructing()) {
124       // TODO (crazybob): if we can't proxy this object, can we proxy the
125
// other object?
126
return constructionContext.createProxy(expectedType);
127     }
128
129     // If we're re-entering this factory while injecting fields or methods,
130
// return the same instance. This prevents infinite loops.
131
T t = constructionContext.getCurrentReference();
132     if (t != null) {
133       return t;
134     }
135
136     try {
137       // First time through...
138
constructionContext.startConstruction();
139       try {
140         Object JavaDoc[] parameters
141             = InjectorImpl.getParameters(context, parameterInjectors);
142         t = constructionProxy.newInstance(parameters);
143         constructionContext.setProxyDelegates(t);
144       }
145       finally {
146         constructionContext.finishConstruction();
147       }
148
149       // Store reference. If an injector re-enters this factory, they'll
150
// get the same reference.
151
constructionContext.setCurrentReference(t);
152
153       // Inject fields and methods.
154
for (InjectorImpl.SingleMemberInjector injector : memberInjectors) {
155         injector.inject(context, t);
156       }
157
158       return t;
159     }
160     catch (InvocationTargetException JavaDoc e) {
161       throw new RuntimeException JavaDoc(e);
162     }
163     finally {
164       constructionContext.removeCurrentReference();
165     }
166   }
167
168   /**
169    * Returns an invalid constructor. This enables us to keep running and
170    * reporting legitimate errors.
171    */

172   static <T> ConstructorInjector<T> invalidConstructor() {
173     return new ConstructorInjector<T>() {
174       Object JavaDoc construct(InternalContext context, Class JavaDoc<?> expectedType) {
175         throw new UnsupportedOperationException JavaDoc();
176       }
177       public T get() {
178         throw new UnsupportedOperationException JavaDoc();
179       }
180     };
181   }
182 }
183
Popular Tags