blob: 6b6303a5a7e78e06a742dea728c534dbd35110bf [file] [log] [blame]
limpbizkit7cef5b02009-03-29 21:16:51 +00001/**
2 * Copyright (C) 2009 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
limpbizkit5ae41eb2009-06-06 17:51:27 +000017package com.google.inject.internal;
limpbizkit7cef5b02009-03-29 21:16:51 +000018
sberlinba75f352011-06-12 21:54:43 +000019import com.google.inject.Key;
limpbizkit5ae41eb2009-06-06 17:51:27 +000020import com.google.inject.MembersInjector;
21import com.google.inject.TypeLiteral;
sberlind9c913a2011-06-26 21:02:54 +000022import com.google.common.collect.ImmutableList;
23import com.google.common.collect.ImmutableSet;
limpbizkit7cef5b02009-03-29 21:16:51 +000024import com.google.inject.spi.InjectionListener;
limpbizkita843a952009-04-08 22:24:55 +000025import com.google.inject.spi.InjectionPoint;
limpbizkit7cef5b02009-03-29 21:16:51 +000026
27/**
28 * Injects members of instances of a given type.
29 *
30 * @author jessewilson@google.com (Jesse Wilson)
31 */
limpbizkit5ae41eb2009-06-06 17:51:27 +000032final class MembersInjectorImpl<T> implements MembersInjector<T> {
limpbizkit7cef5b02009-03-29 21:16:51 +000033 private final TypeLiteral<T> typeLiteral;
34 private final InjectorImpl injector;
35 private final ImmutableList<SingleMemberInjector> memberInjectors;
limpbizkitee792462009-04-08 23:48:49 +000036 private final ImmutableList<MembersInjector<? super T>> userMembersInjectors;
limpbizkit7cef5b02009-03-29 21:16:51 +000037 private final ImmutableList<InjectionListener<? super T>> injectionListeners;
limpbizkiteb405132009-04-14 00:50:25 +000038 /*if[AOP]*/
limpbizkita843a952009-04-08 22:24:55 +000039 private final ImmutableList<MethodAspect> addedAspects;
limpbizkiteb405132009-04-14 00:50:25 +000040 /*end[AOP]*/
limpbizkit7cef5b02009-03-29 21:16:51 +000041
42 MembersInjectorImpl(InjectorImpl injector, TypeLiteral<T> typeLiteral,
limpbizkiteb405132009-04-14 00:50:25 +000043 EncounterImpl<T> encounter, ImmutableList<SingleMemberInjector> memberInjectors) {
limpbizkit7cef5b02009-03-29 21:16:51 +000044 this.injector = injector;
45 this.typeLiteral = typeLiteral;
46 this.memberInjectors = memberInjectors;
limpbizkiteb405132009-04-14 00:50:25 +000047 this.userMembersInjectors = encounter.getMembersInjectors();
48 this.injectionListeners = encounter.getInjectionListeners();
49 /*if[AOP]*/
50 this.addedAspects = encounter.getAspects();
51 /*end[AOP]*/
limpbizkit7cef5b02009-03-29 21:16:51 +000052 }
53
54 public ImmutableList<SingleMemberInjector> getMemberInjectors() {
55 return memberInjectors;
56 }
57
58 public void injectMembers(T instance) {
59 Errors errors = new Errors(typeLiteral);
60 try {
sberlinba75f352011-06-12 21:54:43 +000061 injectAndNotify(instance, errors, null, typeLiteral, false);
limpbizkit7cef5b02009-03-29 21:16:51 +000062 } catch (ErrorsException e) {
63 errors.merge(e.getErrors());
64 }
65
66 errors.throwProvisionExceptionIfErrorsExist();
67 }
68
sberlinba75f352011-06-12 21:54:43 +000069 void injectAndNotify(final T instance, final Errors errors,
70 final Key<T> key, final Object source, final boolean toolableOnly)
71 throws ErrorsException {
limpbizkit7cef5b02009-03-29 21:16:51 +000072 if (instance == null) {
73 return;
74 }
75
76 injector.callInContext(new ContextualCallable<Void>() {
77 public Void call(InternalContext context) throws ErrorsException {
sberlinba75f352011-06-12 21:54:43 +000078 context.pushState(key, source);
79 try {
80 injectMembers(instance, errors, context, toolableOnly);
81 } finally {
82 context.popState();
83 }
limpbizkit7cef5b02009-03-29 21:16:51 +000084 return null;
85 }
86 });
87
sberlin97c22712010-02-05 21:12:05 +000088 // TODO: We *could* notify listeners too here,
89 // but it's not clear if we want to. There's no way to know
90 // if a MembersInjector from the usersMemberInjector list wants
91 // toolable injections, so do we really want to notify
92 // about injection? (We could take a strategy of only notifying
93 // if atleast one InjectionPoint was toolable, in which case
94 // the above callInContext could return 'true' if it injected
95 // anything.)
96 if(!toolableOnly) {
97 notifyListeners(instance, errors);
98 }
limpbizkita843a952009-04-08 22:24:55 +000099 }
100
101 void notifyListeners(T instance, Errors errors) throws ErrorsException {
102 int numErrorsBefore = errors.size();
limpbizkit7cef5b02009-03-29 21:16:51 +0000103 for (InjectionListener<? super T> injectionListener : injectionListeners) {
104 try {
105 injectionListener.afterInjection(instance);
106 } catch (RuntimeException e) {
limpbizkita843a952009-04-08 22:24:55 +0000107 errors.errorNotifyingInjectionListener(injectionListener, typeLiteral, e);
limpbizkit7cef5b02009-03-29 21:16:51 +0000108 }
109 }
limpbizkita843a952009-04-08 22:24:55 +0000110 errors.throwIfNewErrors(numErrorsBefore);
limpbizkit7cef5b02009-03-29 21:16:51 +0000111 }
112
sberlin97c22712010-02-05 21:12:05 +0000113 void injectMembers(T t, Errors errors, InternalContext context, boolean toolableOnly) {
limpbizkite89c49e2009-05-06 01:02:14 +0000114 // optimization: use manual for/each to save allocating an iterator here
115 for (int i = 0, size = memberInjectors.size(); i < size; i++) {
sberlin97c22712010-02-05 21:12:05 +0000116 SingleMemberInjector injector = memberInjectors.get(i);
117 if(!toolableOnly || injector.getInjectionPoint().isToolable()) {
118 injector.inject(errors, context, t);
119 }
limpbizkit7cef5b02009-03-29 21:16:51 +0000120 }
limpbizkitee792462009-04-08 23:48:49 +0000121
sberlin97c22712010-02-05 21:12:05 +0000122 // TODO: There's no way to know if a user's MembersInjector wants toolable injections.
123 if(!toolableOnly) {
limpbizkite89c49e2009-05-06 01:02:14 +0000124 // optimization: use manual for/each to save allocating an iterator here
sberlin97c22712010-02-05 21:12:05 +0000125 for (int i = 0, size = userMembersInjectors.size(); i < size; i++) {
126 MembersInjector<? super T> userMembersInjector = userMembersInjectors.get(i);
127 try {
128 userMembersInjector.injectMembers(t);
129 } catch (RuntimeException e) {
130 errors.errorInUserInjector(userMembersInjector, typeLiteral, e);
131 }
limpbizkitee792462009-04-08 23:48:49 +0000132 }
133 }
limpbizkit7cef5b02009-03-29 21:16:51 +0000134 }
135
136 @Override public String toString() {
137 return "MembersInjector<" + typeLiteral + ">";
138 }
139
140 public ImmutableSet<InjectionPoint> getInjectionPoints() {
141 ImmutableSet.Builder<InjectionPoint> builder = ImmutableSet.builder();
142 for (SingleMemberInjector memberInjector : memberInjectors) {
143 builder.add(memberInjector.getInjectionPoint());
144 }
145 return builder.build();
146 }
147
limpbizkiteb405132009-04-14 00:50:25 +0000148 /*if[AOP]*/
limpbizkita843a952009-04-08 22:24:55 +0000149 public ImmutableList<MethodAspect> getAddedAspects() {
150 return addedAspects;
limpbizkit7cef5b02009-03-29 21:16:51 +0000151 }
limpbizkiteb405132009-04-14 00:50:25 +0000152 /*end[AOP]*/
limpbizkit7cef5b02009-03-29 21:16:51 +0000153}