1/**
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
17package com.google.inject.internal;
18
19import static com.google.common.collect.Iterables.concat;
20
21import com.google.common.collect.ImmutableList;
22import com.google.inject.spi.InjectionPoint;
23
24/**
25 * Constructor injectors by type.
26 *
27 * @author jessewilson@google.com (Jesse Wilson)
28 */
29final class ConstructorInjectorStore {
30  private final InjectorImpl injector;
31
32  private final FailableCache<InjectionPoint, ConstructorInjector<?>>  cache
33      = new FailableCache<InjectionPoint, ConstructorInjector<?>> () {
34    @Override
35    protected ConstructorInjector<?> create(InjectionPoint constructorInjector, Errors errors)
36        throws ErrorsException {
37      return createConstructor(constructorInjector, errors);
38    }
39  };
40
41  ConstructorInjectorStore(InjectorImpl injector) {
42    this.injector = injector;
43  }
44
45  /**
46   * Returns a new complete constructor injector with injection listeners registered.
47   */
48  public ConstructorInjector<?> get(InjectionPoint constructorInjector, Errors errors)
49      throws ErrorsException {
50    return cache.get(constructorInjector, errors);
51  }
52
53  /**
54   * Purges an injection point from the cache. Use this only if the cache is not actually valid and
55   * needs to be purged. (See issue 319 and
56   * ImplicitBindingTest#testCircularJitBindingsLeaveNoResidue and
57   * #testInstancesRequestingProvidersForThemselvesWithChildInjectors for examples of when this is
58   * necessary.)
59   *
60   * Returns true if the injector for that point was stored in the cache, false otherwise.
61   */
62  boolean remove(InjectionPoint ip) {
63    return cache.remove(ip);
64  }
65
66  private <T> ConstructorInjector<T> createConstructor(InjectionPoint injectionPoint, Errors errors)
67      throws ErrorsException {
68    int numErrorsBefore = errors.size();
69
70    SingleParameterInjector<?>[] constructorParameterInjectors
71        = injector.getParametersInjectors(injectionPoint.getDependencies(), errors);
72
73    @SuppressWarnings("unchecked") // the injector type agrees with the injection point type
74    MembersInjectorImpl<T> membersInjector = (MembersInjectorImpl<T>) injector.membersInjectorStore
75        .get(injectionPoint.getDeclaringType(), errors);
76
77    /*if[AOP]*/
78    ImmutableList<MethodAspect> injectorAspects = injector.state.getMethodAspects();
79    ImmutableList<MethodAspect> methodAspects = membersInjector.getAddedAspects().isEmpty()
80        ? injectorAspects
81        : ImmutableList.copyOf(concat(injectorAspects, membersInjector.getAddedAspects()));
82    ConstructionProxyFactory<T> factory = new ProxyFactory<T>(injectionPoint, methodAspects);
83    /*end[AOP]*/
84    /*if[NO_AOP]
85    ConstructionProxyFactory<T> factory = new DefaultConstructionProxyFactory<T>(injectionPoint);
86    end[NO_AOP]*/
87
88    errors.throwIfNewErrors(numErrorsBefore);
89
90    return new ConstructorInjector<T>(membersInjector.getInjectionPoints(), factory.create(),
91        constructorParameterInjectors, membersInjector);
92  }
93}
94