Home | History | Annotate | Download | only in codegen
      1 /*
      2  * Copyright (C) 2014 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 package dagger.internal.codegen;
     17 
     18 import com.google.auto.common.MoreTypes;
     19 import com.google.auto.value.AutoValue;
     20 import com.google.common.base.Optional;
     21 import com.google.common.collect.ImmutableList;
     22 import com.google.common.collect.ImmutableSet;
     23 import com.google.common.collect.Sets;
     24 import com.google.common.util.concurrent.ListenableFuture;
     25 import dagger.Provides;
     26 import dagger.producers.Produces;
     27 import java.util.Set;
     28 import javax.lang.model.element.ExecutableElement;
     29 import javax.lang.model.element.TypeElement;
     30 import javax.lang.model.type.DeclaredType;
     31 import javax.lang.model.type.ExecutableType;
     32 import javax.lang.model.type.TypeKind;
     33 import javax.lang.model.type.TypeMirror;
     34 import javax.lang.model.util.Types;
     35 
     36 import static com.google.common.base.Preconditions.checkArgument;
     37 import static com.google.common.base.Preconditions.checkNotNull;
     38 import static javax.lang.model.element.ElementKind.METHOD;
     39 
     40 /**
     41  * A value object representing the mechanism by which a {@link Key} can be produced. New instances
     42  * should be created using an instance of the {@link Factory}.
     43  *
     44  * @author Jesse Beder
     45  * @since 2.0
     46  */
     47 @AutoValue
     48 abstract class ProductionBinding extends ContributionBinding {
     49 
     50   @Override
     51   Binding.Type bindingType() {
     52     return Binding.Type.PRODUCTION;
     53   }
     54 
     55   @Override
     56   Provides.Type provisionType() {
     57     return Provides.Type.valueOf(productionType().name());
     58   }
     59 
     60   @Override
     61   Set<DependencyRequest> implicitDependencies() {
     62     // Similar optimizations to ContributionBinding.implicitDependencies().
     63     if (!monitorRequest().isPresent()) {
     64       return super.implicitDependencies();
     65     } else {
     66       return Sets.union(monitorRequest().asSet(), super.implicitDependencies());
     67     }
     68   }
     69 
     70   /** Returns provision type that was used to bind the key. */
     71   abstract Produces.Type productionType();
     72 
     73   /** Returns the list of types in the throws clause of the method. */
     74   abstract ImmutableList<? extends TypeMirror> thrownTypes();
     75 
     76   /** If this production requires a monitor, this will be the corresponding request. */
     77   abstract Optional<DependencyRequest> monitorRequest();
     78 
     79   @Override
     80   ContributionType contributionType() {
     81     switch (productionType()) {
     82       case SET:
     83       case SET_VALUES:
     84         return ContributionType.SET;
     85       case MAP:
     86         return ContributionType.MAP;
     87       case UNIQUE:
     88         return ContributionType.UNIQUE;
     89       default:
     90         throw new AssertionError("Unknown production type: " + productionType());
     91     }
     92   }
     93 
     94   static final class Factory {
     95     private final Types types;
     96     private final Key.Factory keyFactory;
     97     private final DependencyRequest.Factory dependencyRequestFactory;
     98 
     99     Factory(
    100         Types types, Key.Factory keyFactory, DependencyRequest.Factory dependencyRequestFactory) {
    101       this.types = types;
    102       this.keyFactory = keyFactory;
    103       this.dependencyRequestFactory = dependencyRequestFactory;
    104     }
    105 
    106     ProductionBinding forProducesMethod(
    107         ExecutableElement producesMethod, TypeMirror contributedBy) {
    108       checkNotNull(producesMethod);
    109       checkArgument(producesMethod.getKind().equals(METHOD));
    110       checkArgument(contributedBy.getKind().equals(TypeKind.DECLARED));
    111       Produces producesAnnotation = producesMethod.getAnnotation(Produces.class);
    112       checkArgument(producesAnnotation != null);
    113       DeclaredType declaredContainer = MoreTypes.asDeclared(contributedBy);
    114       ExecutableType resolvedMethod =
    115           MoreTypes.asExecutable(types.asMemberOf(declaredContainer, producesMethod));
    116       Key key = keyFactory.forProducesMethod(resolvedMethod, producesMethod);
    117       ImmutableSet<DependencyRequest> dependencies =
    118           dependencyRequestFactory.forRequiredResolvedVariables(
    119               declaredContainer,
    120               producesMethod.getParameters(),
    121               resolvedMethod.getParameterTypes());
    122       DependencyRequest monitorRequest =
    123           dependencyRequestFactory.forProductionComponentMonitorProvider();
    124       Kind kind = MoreTypes.isTypeOf(ListenableFuture.class, producesMethod.getReturnType())
    125           ? Kind.FUTURE_PRODUCTION
    126           : Kind.IMMEDIATE;
    127       return new AutoValue_ProductionBinding(
    128           key,
    129           producesMethod,
    130           dependencies,
    131           findBindingPackage(key),
    132           false,
    133           ConfigurationAnnotations.getNullableType(producesMethod),
    134           Optional.of(MoreTypes.asTypeElement(declaredContainer)),
    135           Optional.<DependencyRequest>absent(),
    136           kind,
    137           producesAnnotation.type(),
    138           ImmutableList.copyOf(producesMethod.getThrownTypes()),
    139           Optional.of(monitorRequest));
    140     }
    141 
    142     ProductionBinding implicitMapOfProducerBinding(DependencyRequest mapOfValueRequest) {
    143       checkNotNull(mapOfValueRequest);
    144       Optional<Key> implicitMapOfProducerKey =
    145           keyFactory.implicitMapProducerKeyFrom(mapOfValueRequest.key());
    146       checkArgument(
    147           implicitMapOfProducerKey.isPresent(), "%s is not for a Map<K, V>", mapOfValueRequest);
    148       DependencyRequest implicitMapOfProducerRequest =
    149           dependencyRequestFactory.forImplicitMapBinding(
    150               mapOfValueRequest, implicitMapOfProducerKey.get());
    151       return new AutoValue_ProductionBinding(
    152           mapOfValueRequest.key(),
    153           implicitMapOfProducerRequest.requestElement(),
    154           ImmutableSet.of(implicitMapOfProducerRequest),
    155           findBindingPackage(mapOfValueRequest.key()),
    156           false,
    157           Optional.<DeclaredType>absent(),
    158           Optional.<TypeElement>absent(),
    159           Optional.<DependencyRequest>absent(),
    160           Kind.SYNTHETIC,
    161           Produces.Type.MAP,
    162           ImmutableList.<TypeMirror>of(),
    163           Optional.<DependencyRequest>absent());
    164     }
    165 
    166     ProductionBinding forComponentMethod(ExecutableElement componentMethod) {
    167       checkNotNull(componentMethod);
    168       checkArgument(componentMethod.getKind().equals(METHOD));
    169       checkArgument(componentMethod.getParameters().isEmpty());
    170       checkArgument(MoreTypes.isTypeOf(ListenableFuture.class, componentMethod.getReturnType()));
    171       return new AutoValue_ProductionBinding(
    172           keyFactory.forProductionComponentMethod(componentMethod),
    173           componentMethod,
    174           ImmutableSet.<DependencyRequest>of(),
    175           Optional.<String>absent(),
    176           false,
    177           Optional.<DeclaredType>absent(),
    178           Optional.<TypeElement>absent(),
    179           Optional.<DependencyRequest>absent(),
    180           Kind.COMPONENT_PRODUCTION,
    181           Produces.Type.UNIQUE,
    182           ImmutableList.copyOf(componentMethod.getThrownTypes()),
    183           Optional.<DependencyRequest>absent());
    184     }
    185   }
    186 }
    187