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 | |
limpbizkit | 5ae41eb | 2009-06-06 17:51:27 +0000 | [diff] [blame] | 17 | package com.google.inject.internal; |
crazyboblee | e3adfd6 | 2007-02-02 21:30:08 +0000 | [diff] [blame] | 18 | |
sberlin | d9c913a | 2011-06-26 21:02:54 +0000 | [diff] [blame] | 19 | import com.google.common.collect.ImmutableSet; |
sberlin | b7a02b0 | 2011-07-08 00:34:16 +0000 | [diff] [blame] | 20 | import com.google.inject.internal.ProvisionListenerStackCallback.ProvisionCallback; |
limpbizkit | a843a95 | 2009-04-08 22:24:55 +0000 | [diff] [blame] | 21 | import com.google.inject.spi.InjectionPoint; |
sberlin | b7a02b0 | 2011-07-08 00:34:16 +0000 | [diff] [blame] | 22 | |
crazyboblee | e3adfd6 | 2007-02-02 21:30:08 +0000 | [diff] [blame] | 23 | import java.lang.reflect.InvocationTargetException; |
limpbizkit | 9b8bdc7 | 2009-06-07 19:37:28 +0000 | [diff] [blame] | 24 | import java.util.Set; |
crazyboblee | e3adfd6 | 2007-02-02 21:30:08 +0000 | [diff] [blame] | 25 | |
| 26 | /** |
limpbizkit | 0689806 | 2008-11-02 05:14:55 +0000 | [diff] [blame] | 27 | * Creates instances using an injectable constructor. After construction, all injectable fields and |
| 28 | * methods are injected. |
crazyboblee | e3adfd6 | 2007-02-02 21:30:08 +0000 | [diff] [blame] | 29 | * |
| 30 | * @author crazybob@google.com (Bob Lee) |
kevinb9n | a99dca7 | 2007-02-11 04:48:57 +0000 | [diff] [blame] | 31 | */ |
limpbizkit | 5ae41eb | 2009-06-06 17:51:27 +0000 | [diff] [blame] | 32 | final class ConstructorInjector<T> { |
crazyboblee | e3adfd6 | 2007-02-02 21:30:08 +0000 | [diff] [blame] | 33 | |
limpbizkit | a843a95 | 2009-04-08 22:24:55 +0000 | [diff] [blame] | 34 | private final ImmutableSet<InjectionPoint> injectableMembers; |
limpbizkit | e89c49e | 2009-05-06 01:02:14 +0000 | [diff] [blame] | 35 | private final SingleParameterInjector<?>[] parameterInjectors; |
limpbizkit | 03b81a6 | 2009-03-18 05:34:39 +0000 | [diff] [blame] | 36 | private final ConstructionProxy<T> constructionProxy; |
limpbizkit | 7cef5b0 | 2009-03-29 21:16:51 +0000 | [diff] [blame] | 37 | private final MembersInjectorImpl<T> membersInjector; |
crazyboblee | e3adfd6 | 2007-02-02 21:30:08 +0000 | [diff] [blame] | 38 | |
limpbizkit | 9b8bdc7 | 2009-06-07 19:37:28 +0000 | [diff] [blame] | 39 | ConstructorInjector(Set<InjectionPoint> injectableMembers, |
limpbizkit | a843a95 | 2009-04-08 22:24:55 +0000 | [diff] [blame] | 40 | ConstructionProxy<T> constructionProxy, |
limpbizkit | e89c49e | 2009-05-06 01:02:14 +0000 | [diff] [blame] | 41 | SingleParameterInjector<?>[] parameterInjectors, |
limpbizkit | 9b8bdc7 | 2009-06-07 19:37:28 +0000 | [diff] [blame] | 42 | MembersInjectorImpl<T> membersInjector) { |
| 43 | this.injectableMembers = ImmutableSet.copyOf(injectableMembers); |
limpbizkit | 03b81a6 | 2009-03-18 05:34:39 +0000 | [diff] [blame] | 44 | this.constructionProxy = constructionProxy; |
| 45 | this.parameterInjectors = parameterInjectors; |
limpbizkit | 7cef5b0 | 2009-03-29 21:16:51 +0000 | [diff] [blame] | 46 | this.membersInjector = membersInjector; |
limpbizkit | a843a95 | 2009-04-08 22:24:55 +0000 | [diff] [blame] | 47 | } |
| 48 | |
| 49 | public ImmutableSet<InjectionPoint> getInjectableMembers() { |
| 50 | return injectableMembers; |
| 51 | } |
| 52 | |
limpbizkit | a843a95 | 2009-04-08 22:24:55 +0000 | [diff] [blame] | 53 | ConstructionProxy<T> getConstructionProxy() { |
| 54 | return constructionProxy; |
crazyboblee | e3adfd6 | 2007-02-02 21:30:08 +0000 | [diff] [blame] | 55 | } |
| 56 | |
crazyboblee | e3adfd6 | 2007-02-02 21:30:08 +0000 | [diff] [blame] | 57 | /** |
kevinb9n | a99dca7 | 2007-02-11 04:48:57 +0000 | [diff] [blame] | 58 | * Construct an instance. Returns {@code Object} instead of {@code T} because |
| 59 | * it may return a proxy. |
crazyboblee | e3adfd6 | 2007-02-02 21:30:08 +0000 | [diff] [blame] | 60 | */ |
sberlin | 132a5db | 2011-06-05 18:32:05 +0000 | [diff] [blame] | 61 | Object construct(final Errors errors, final InternalContext context, |
timofeyb | 5e6c933 | 2015-04-20 12:45:07 -0700 | [diff] [blame^] | 62 | Class<?> expectedType, |
sberlin | 132a5db | 2011-06-05 18:32:05 +0000 | [diff] [blame] | 63 | ProvisionListenerStackCallback<T> provisionCallback) |
limpbizkit | 163c48a | 2008-06-16 02:58:08 +0000 | [diff] [blame] | 64 | throws ErrorsException { |
sberlin | 132a5db | 2011-06-05 18:32:05 +0000 | [diff] [blame] | 65 | final ConstructionContext<T> constructionContext = context.getConstructionContext(this); |
crazyboblee | e3adfd6 | 2007-02-02 21:30:08 +0000 | [diff] [blame] | 66 | |
| 67 | // We have a circular reference between constructors. Return a proxy. |
| 68 | if (constructionContext.isConstructing()) { |
timofeyb | 5e6c933 | 2015-04-20 12:45:07 -0700 | [diff] [blame^] | 69 | // TODO (crazybob): if we can't proxy this object, can we proxy the other object? |
| 70 | return constructionContext.createProxy( |
| 71 | errors, context.getInjectorOptions(), expectedType); |
crazyboblee | e3adfd6 | 2007-02-02 21:30:08 +0000 | [diff] [blame] | 72 | } |
| 73 | |
| 74 | // If we're re-entering this factory while injecting fields or methods, |
| 75 | // return the same instance. This prevents infinite loops. |
| 76 | T t = constructionContext.getCurrentReference(); |
| 77 | if (t != null) { |
| 78 | return t; |
| 79 | } |
| 80 | |
Sam Berlin | d51292d | 2012-02-26 21:23:19 -0500 | [diff] [blame] | 81 | constructionContext.startConstruction(); |
crazyboblee | e3adfd6 | 2007-02-02 21:30:08 +0000 | [diff] [blame] | 82 | try { |
sberlin | 132a5db | 2011-06-05 18:32:05 +0000 | [diff] [blame] | 83 | // Optimization: Don't go through the callback stack if we have no listeners. |
| 84 | if (!provisionCallback.hasListeners()) { |
timofeyb | 5e6c933 | 2015-04-20 12:45:07 -0700 | [diff] [blame^] | 85 | return provision(errors, context, constructionContext); |
sberlin | 132a5db | 2011-06-05 18:32:05 +0000 | [diff] [blame] | 86 | } else { |
sberlin | ba75f35 | 2011-06-12 21:54:43 +0000 | [diff] [blame] | 87 | return provisionCallback.provision(errors, context, new ProvisionCallback<T>() { |
sberlin | 132a5db | 2011-06-05 18:32:05 +0000 | [diff] [blame] | 88 | public T call() throws ErrorsException { |
| 89 | return provision(errors, context, constructionContext); |
| 90 | } |
| 91 | }); |
| 92 | } |
| 93 | } finally { |
Sam Berlin | d51292d | 2012-02-26 21:23:19 -0500 | [diff] [blame] | 94 | constructionContext.finishConstruction(); |
sberlin | 132a5db | 2011-06-05 18:32:05 +0000 | [diff] [blame] | 95 | } |
| 96 | } |
| 97 | |
| 98 | /** Provisions a new T. */ |
| 99 | private T provision(Errors errors, InternalContext context, |
| 100 | ConstructionContext<T> constructionContext) throws ErrorsException { |
| 101 | try { |
sberlin | 132a5db | 2011-06-05 18:32:05 +0000 | [diff] [blame] | 102 | T t; |
crazyboblee | e3adfd6 | 2007-02-02 21:30:08 +0000 | [diff] [blame] | 103 | try { |
limpbizkit | 0689806 | 2008-11-02 05:14:55 +0000 | [diff] [blame] | 104 | Object[] parameters = SingleParameterInjector.getAll(errors, context, parameterInjectors); |
kevinb9n | 48d1307 | 2007-02-12 18:21:26 +0000 | [diff] [blame] | 105 | t = constructionProxy.newInstance(parameters); |
crazyboblee | e3adfd6 | 2007-02-02 21:30:08 +0000 | [diff] [blame] | 106 | constructionContext.setProxyDelegates(t); |
limpbizkit | 0689806 | 2008-11-02 05:14:55 +0000 | [diff] [blame] | 107 | } finally { |
crazyboblee | e3adfd6 | 2007-02-02 21:30:08 +0000 | [diff] [blame] | 108 | constructionContext.finishConstruction(); |
| 109 | } |
Christian Edward Gruber | 9e2d95b | 2013-06-26 17:43:11 -0700 | [diff] [blame] | 110 | |
limpbizkit | a843a95 | 2009-04-08 22:24:55 +0000 | [diff] [blame] | 111 | // Store reference. If an injector re-enters this factory, they'll get the same reference. |
crazyboblee | e3adfd6 | 2007-02-02 21:30:08 +0000 | [diff] [blame] | 112 | constructionContext.setCurrentReference(t); |
Christian Edward Gruber | 9e2d95b | 2013-06-26 17:43:11 -0700 | [diff] [blame] | 113 | |
sberlin | 97c2271 | 2010-02-05 21:12:05 +0000 | [diff] [blame] | 114 | membersInjector.injectMembers(t, errors, context, false); |
limpbizkit | a843a95 | 2009-04-08 22:24:55 +0000 | [diff] [blame] | 115 | membersInjector.notifyListeners(t, errors); |
Christian Edward Gruber | 9e2d95b | 2013-06-26 17:43:11 -0700 | [diff] [blame] | 116 | |
crazyboblee | e3adfd6 | 2007-02-02 21:30:08 +0000 | [diff] [blame] | 117 | return t; |
limpbizkit | a6e0e78 | 2008-09-03 06:19:56 +0000 | [diff] [blame] | 118 | } catch (InvocationTargetException userException) { |
limpbizkit | 9dc32d4 | 2008-06-15 11:29:10 +0000 | [diff] [blame] | 119 | Throwable cause = userException.getCause() != null |
| 120 | ? userException.getCause() |
| 121 | : userException; |
limpbizkit | a6e0e78 | 2008-09-03 06:19:56 +0000 | [diff] [blame] | 122 | throw errors.withSource(constructionProxy.getInjectionPoint()) |
| 123 | .errorInjectingConstructor(cause).toException(); |
Christian Edward Gruber | 2cc8ce9 | 2013-05-16 10:53:11 -0700 | [diff] [blame] | 124 | } finally { |
| 125 | constructionContext.removeCurrentReference(); |
crazyboblee | e3adfd6 | 2007-02-02 21:30:08 +0000 | [diff] [blame] | 126 | } |
| 127 | } |
crazyboblee | e3adfd6 | 2007-02-02 21:30:08 +0000 | [diff] [blame] | 128 | } |