crazyboblee | b8cf1e5 | 2007-02-02 21:48:16 +0000 | [diff] [blame] | 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 | */ |
crazyboblee | e3adfd6 | 2007-02-02 21:30:08 +0000 | [diff] [blame] | 16 | |
| 17 | package com.google.inject; |
| 18 | |
limpbizkit | 916f548 | 2008-04-16 20:51:14 +0000 | [diff] [blame] | 19 | import com.google.inject.internal.ErrorMessages; |
limpbizkit | 3b1cd58 | 2008-04-28 00:06:01 +0000 | [diff] [blame] | 20 | import com.google.inject.internal.ResolveFailedException; |
limpbizkit | 916f548 | 2008-04-16 20:51:14 +0000 | [diff] [blame] | 21 | |
crazyboblee | e3adfd6 | 2007-02-02 21:30:08 +0000 | [diff] [blame] | 22 | import java.lang.reflect.InvocationTargetException; |
| 23 | |
| 24 | /** |
| 25 | * Injects constructors. |
| 26 | * |
| 27 | * @author crazybob@google.com (Bob Lee) |
kevinb9n | a99dca7 | 2007-02-11 04:48:57 +0000 | [diff] [blame] | 28 | */ |
crazyboblee | 0789b19 | 2007-02-13 02:43:28 +0000 | [diff] [blame] | 29 | class ConstructorInjector<T> { |
crazyboblee | e3adfd6 | 2007-02-02 21:30:08 +0000 | [diff] [blame] | 30 | |
| 31 | final Class<T> implementation; |
kevinb9n | a2915a9 | 2007-02-28 06:20:30 +0000 | [diff] [blame] | 32 | final InjectorImpl.SingleMemberInjector[] memberInjectors; |
| 33 | final InjectorImpl.SingleParameterInjector<?>[] parameterInjectors; |
crazyboblee | e3adfd6 | 2007-02-02 21:30:08 +0000 | [diff] [blame] | 34 | final ConstructionProxy<T> constructionProxy; |
| 35 | |
kevinb9n | a2915a9 | 2007-02-28 06:20:30 +0000 | [diff] [blame] | 36 | ConstructorInjector(InjectorImpl injector, Class<T> implementation) { |
crazyboblee | e3adfd6 | 2007-02-02 21:30:08 +0000 | [diff] [blame] | 37 | this.implementation = implementation; |
limpbizkit | 916f548 | 2008-04-16 20:51:14 +0000 | [diff] [blame] | 38 | constructionProxy = injector.reflection.getConstructionProxy(implementation); |
| 39 | parameterInjectors = createParameterInjector(injector, constructionProxy); |
kevinb9n | a2915a9 | 2007-02-28 06:20:30 +0000 | [diff] [blame] | 40 | memberInjectors = injector.injectors.get(implementation) |
| 41 | .toArray(new InjectorImpl.SingleMemberInjector[0]); |
crazyboblee | e3adfd6 | 2007-02-02 21:30:08 +0000 | [diff] [blame] | 42 | } |
| 43 | |
crazyboblee | 0789b19 | 2007-02-13 02:43:28 +0000 | [diff] [blame] | 44 | /** |
| 45 | * Used to create an invalid injector. |
| 46 | */ |
| 47 | private ConstructorInjector() { |
| 48 | implementation = null; |
kevinb9n | a2915a9 | 2007-02-28 06:20:30 +0000 | [diff] [blame] | 49 | memberInjectors = null; |
crazyboblee | 0789b19 | 2007-02-13 02:43:28 +0000 | [diff] [blame] | 50 | parameterInjectors = null; |
| 51 | constructionProxy = null; |
| 52 | } |
| 53 | |
kevinb9n | a2915a9 | 2007-02-28 06:20:30 +0000 | [diff] [blame] | 54 | InjectorImpl.SingleParameterInjector<?>[] createParameterInjector( |
limpbizkit | 916f548 | 2008-04-16 20:51:14 +0000 | [diff] [blame] | 55 | InjectorImpl injector, ConstructionProxy<T> constructionProxy) { |
crazyboblee | e3adfd6 | 2007-02-02 21:30:08 +0000 | [diff] [blame] | 56 | try { |
limpbizkit | 916f548 | 2008-04-16 20:51:14 +0000 | [diff] [blame] | 57 | return constructionProxy.getParameters().isEmpty() |
crazyboblee | e3adfd6 | 2007-02-02 21:30:08 +0000 | [diff] [blame] | 58 | ? null // default constructor. |
kevinb9n | a2915a9 | 2007-02-28 06:20:30 +0000 | [diff] [blame] | 59 | : injector.getParametersInjectors( |
limpbizkit | 916f548 | 2008-04-16 20:51:14 +0000 | [diff] [blame] | 60 | constructionProxy.getMember(), |
| 61 | constructionProxy.getParameters()); |
kevinb9n | a99dca7 | 2007-02-11 04:48:57 +0000 | [diff] [blame] | 62 | } |
limpbizkit | 3b1cd58 | 2008-04-28 00:06:01 +0000 | [diff] [blame] | 63 | catch (ResolveFailedException e) { |
| 64 | injector.errorHandler.handle(constructionProxy.getMember(), e.getMessage()); |
crazyboblee | e3adfd6 | 2007-02-02 21:30:08 +0000 | [diff] [blame] | 65 | return null; |
| 66 | } |
| 67 | } |
| 68 | |
crazyboblee | e3adfd6 | 2007-02-02 21:30:08 +0000 | [diff] [blame] | 69 | /** |
kevinb9n | a99dca7 | 2007-02-11 04:48:57 +0000 | [diff] [blame] | 70 | * Construct an instance. Returns {@code Object} instead of {@code T} because |
| 71 | * it may return a proxy. |
crazyboblee | e3adfd6 | 2007-02-02 21:30:08 +0000 | [diff] [blame] | 72 | */ |
crazyboblee | edda436 | 2007-03-02 02:55:35 +0000 | [diff] [blame] | 73 | Object construct(InternalContext context, Class<?> expectedType) { |
kevinb9n | a99dca7 | 2007-02-11 04:48:57 +0000 | [diff] [blame] | 74 | ConstructionContext<T> constructionContext |
| 75 | = context.getConstructionContext(this); |
crazyboblee | e3adfd6 | 2007-02-02 21:30:08 +0000 | [diff] [blame] | 76 | |
| 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 { |
kevinb9n | a99dca7 | 2007-02-11 04:48:57 +0000 | [diff] [blame] | 95 | Object[] parameters |
kevinb9n | a2915a9 | 2007-02-28 06:20:30 +0000 | [diff] [blame] | 96 | = InjectorImpl.getParameters(context, parameterInjectors); |
kevinb9n | 48d1307 | 2007-02-12 18:21:26 +0000 | [diff] [blame] | 97 | t = constructionProxy.newInstance(parameters); |
crazyboblee | e3adfd6 | 2007-02-02 21:30:08 +0000 | [diff] [blame] | 98 | constructionContext.setProxyDelegates(t); |
kevinb9n | a99dca7 | 2007-02-11 04:48:57 +0000 | [diff] [blame] | 99 | } |
| 100 | finally { |
crazyboblee | e3adfd6 | 2007-02-02 21:30:08 +0000 | [diff] [blame] | 101 | 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. |
kevinb9n | a2915a9 | 2007-02-28 06:20:30 +0000 | [diff] [blame] | 109 | for (InjectorImpl.SingleMemberInjector injector : memberInjectors) { |
kevinb9n | a99dca7 | 2007-02-11 04:48:57 +0000 | [diff] [blame] | 110 | injector.inject(context, t); |
crazyboblee | e3adfd6 | 2007-02-02 21:30:08 +0000 | [diff] [blame] | 111 | } |
| 112 | |
| 113 | return t; |
kevinb9n | a99dca7 | 2007-02-11 04:48:57 +0000 | [diff] [blame] | 114 | } |
| 115 | catch (InvocationTargetException e) { |
limpbizkit | 1dabcfd | 2007-08-25 08:06:30 +0000 | [diff] [blame] | 116 | Throwable cause = e.getCause() != null ? e.getCause() : e; |
limpbizkit | fcf2b8c | 2007-10-21 18:23:43 +0000 | [diff] [blame] | 117 | throw new ProvisionException(cause, |
| 118 | ErrorMessages.ERROR_INJECTING_CONSTRUCTOR); |
kevinb9n | a99dca7 | 2007-02-11 04:48:57 +0000 | [diff] [blame] | 119 | } |
| 120 | finally { |
crazyboblee | e3adfd6 | 2007-02-02 21:30:08 +0000 | [diff] [blame] | 121 | constructionContext.removeCurrentReference(); |
| 122 | } |
| 123 | } |
| 124 | |
crazyboblee | 0789b19 | 2007-02-13 02:43:28 +0000 | [diff] [blame] | 125 | /** |
| 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>() { |
crazyboblee | edda436 | 2007-03-02 02:55:35 +0000 | [diff] [blame] | 131 | Object construct(InternalContext context, Class<?> expectedType) { |
crazyboblee | 0789b19 | 2007-02-13 02:43:28 +0000 | [diff] [blame] | 132 | throw new UnsupportedOperationException(); |
| 133 | } |
| 134 | public T get() { |
| 135 | throw new UnsupportedOperationException(); |
| 136 | } |
| 137 | }; |
crazyboblee | e3adfd6 | 2007-02-02 21:30:08 +0000 | [diff] [blame] | 138 | } |
| 139 | } |