blob: b501a4114a39029d59a3fbf48805f0791f28aef3 [file] [log] [blame]
crazybobleeb8cf1e52007-02-02 21:48:16 +00001/**
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 */
crazybobleee3adfd62007-02-02 21:30:08 +000016
17package com.google.inject;
18
limpbizkit916f5482008-04-16 20:51:14 +000019import com.google.inject.internal.ErrorMessages;
limpbizkit3b1cd582008-04-28 00:06:01 +000020import com.google.inject.internal.ResolveFailedException;
limpbizkit916f5482008-04-16 20:51:14 +000021
crazybobleee3adfd62007-02-02 21:30:08 +000022import java.lang.reflect.InvocationTargetException;
23
24/**
25 * Injects constructors.
26 *
27 * @author crazybob@google.com (Bob Lee)
kevinb9na99dca72007-02-11 04:48:57 +000028 */
crazyboblee0789b192007-02-13 02:43:28 +000029class ConstructorInjector<T> {
crazybobleee3adfd62007-02-02 21:30:08 +000030
31 final Class<T> implementation;
kevinb9na2915a92007-02-28 06:20:30 +000032 final InjectorImpl.SingleMemberInjector[] memberInjectors;
33 final InjectorImpl.SingleParameterInjector<?>[] parameterInjectors;
crazybobleee3adfd62007-02-02 21:30:08 +000034 final ConstructionProxy<T> constructionProxy;
35
kevinb9na2915a92007-02-28 06:20:30 +000036 ConstructorInjector(InjectorImpl injector, Class<T> implementation) {
crazybobleee3adfd62007-02-02 21:30:08 +000037 this.implementation = implementation;
limpbizkit916f5482008-04-16 20:51:14 +000038 constructionProxy = injector.reflection.getConstructionProxy(implementation);
39 parameterInjectors = createParameterInjector(injector, constructionProxy);
kevinb9na2915a92007-02-28 06:20:30 +000040 memberInjectors = injector.injectors.get(implementation)
41 .toArray(new InjectorImpl.SingleMemberInjector[0]);
crazybobleee3adfd62007-02-02 21:30:08 +000042 }
43
crazyboblee0789b192007-02-13 02:43:28 +000044 /**
45 * Used to create an invalid injector.
46 */
47 private ConstructorInjector() {
48 implementation = null;
kevinb9na2915a92007-02-28 06:20:30 +000049 memberInjectors = null;
crazyboblee0789b192007-02-13 02:43:28 +000050 parameterInjectors = null;
51 constructionProxy = null;
52 }
53
kevinb9na2915a92007-02-28 06:20:30 +000054 InjectorImpl.SingleParameterInjector<?>[] createParameterInjector(
limpbizkit916f5482008-04-16 20:51:14 +000055 InjectorImpl injector, ConstructionProxy<T> constructionProxy) {
crazybobleee3adfd62007-02-02 21:30:08 +000056 try {
limpbizkit916f5482008-04-16 20:51:14 +000057 return constructionProxy.getParameters().isEmpty()
crazybobleee3adfd62007-02-02 21:30:08 +000058 ? null // default constructor.
kevinb9na2915a92007-02-28 06:20:30 +000059 : injector.getParametersInjectors(
limpbizkit916f5482008-04-16 20:51:14 +000060 constructionProxy.getMember(),
61 constructionProxy.getParameters());
kevinb9na99dca72007-02-11 04:48:57 +000062 }
limpbizkit3b1cd582008-04-28 00:06:01 +000063 catch (ResolveFailedException e) {
64 injector.errorHandler.handle(constructionProxy.getMember(), e.getMessage());
crazybobleee3adfd62007-02-02 21:30:08 +000065 return null;
66 }
67 }
68
crazybobleee3adfd62007-02-02 21:30:08 +000069 /**
kevinb9na99dca72007-02-11 04:48:57 +000070 * Construct an instance. Returns {@code Object} instead of {@code T} because
71 * it may return a proxy.
crazybobleee3adfd62007-02-02 21:30:08 +000072 */
crazybobleeedda4362007-03-02 02:55:35 +000073 Object construct(InternalContext context, Class<?> expectedType) {
kevinb9na99dca72007-02-11 04:48:57 +000074 ConstructionContext<T> constructionContext
75 = context.getConstructionContext(this);
crazybobleee3adfd62007-02-02 21:30:08 +000076
77 // We have a circular reference between constructors. Return a proxy.
78 if (constructionContext.isConstructing()) {
79 // TODO (crazybob): if we can't proxy this object, can we proxy the
80 // other object?
81 return constructionContext.createProxy(expectedType);
82 }
83
84 // If we're re-entering this factory while injecting fields or methods,
85 // return the same instance. This prevents infinite loops.
86 T t = constructionContext.getCurrentReference();
87 if (t != null) {
88 return t;
89 }
90
91 try {
92 // First time through...
93 constructionContext.startConstruction();
94 try {
kevinb9na99dca72007-02-11 04:48:57 +000095 Object[] parameters
kevinb9na2915a92007-02-28 06:20:30 +000096 = InjectorImpl.getParameters(context, parameterInjectors);
kevinb9n48d13072007-02-12 18:21:26 +000097 t = constructionProxy.newInstance(parameters);
crazybobleee3adfd62007-02-02 21:30:08 +000098 constructionContext.setProxyDelegates(t);
kevinb9na99dca72007-02-11 04:48:57 +000099 }
100 finally {
crazybobleee3adfd62007-02-02 21:30:08 +0000101 constructionContext.finishConstruction();
102 }
103
104 // Store reference. If an injector re-enters this factory, they'll
105 // get the same reference.
106 constructionContext.setCurrentReference(t);
107
108 // Inject fields and methods.
kevinb9na2915a92007-02-28 06:20:30 +0000109 for (InjectorImpl.SingleMemberInjector injector : memberInjectors) {
kevinb9na99dca72007-02-11 04:48:57 +0000110 injector.inject(context, t);
crazybobleee3adfd62007-02-02 21:30:08 +0000111 }
112
113 return t;
kevinb9na99dca72007-02-11 04:48:57 +0000114 }
115 catch (InvocationTargetException e) {
limpbizkit1dabcfd2007-08-25 08:06:30 +0000116 Throwable cause = e.getCause() != null ? e.getCause() : e;
limpbizkitfcf2b8c2007-10-21 18:23:43 +0000117 throw new ProvisionException(cause,
118 ErrorMessages.ERROR_INJECTING_CONSTRUCTOR);
kevinb9na99dca72007-02-11 04:48:57 +0000119 }
120 finally {
crazybobleee3adfd62007-02-02 21:30:08 +0000121 constructionContext.removeCurrentReference();
122 }
123 }
124
crazyboblee0789b192007-02-13 02:43:28 +0000125 /**
126 * Returns an invalid constructor. This enables us to keep running and
127 * reporting legitimate errors.
128 */
129 static <T> ConstructorInjector<T> invalidConstructor() {
130 return new ConstructorInjector<T>() {
crazybobleeedda4362007-03-02 02:55:35 +0000131 Object construct(InternalContext context, Class<?> expectedType) {
crazyboblee0789b192007-02-13 02:43:28 +0000132 throw new UnsupportedOperationException();
133 }
134 public T get() {
135 throw new UnsupportedOperationException();
136 }
137 };
crazybobleee3adfd62007-02-02 21:30:08 +0000138 }
139}