• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 The Dagger Authors.
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 
17 package dagger.spi.model;
18 
19 import com.google.auto.value.AutoValue;
20 import com.google.auto.value.extension.memoized.Memoized;
21 import com.google.common.base.Joiner;
22 import com.google.errorprone.annotations.CanIgnoreReturnValue;
23 import com.google.errorprone.annotations.CheckReturnValue;
24 import java.util.Objects;
25 import java.util.Optional;
26 import javax.lang.model.element.ExecutableElement;
27 import javax.lang.model.element.TypeElement;
28 
29 /**
30  * A {@linkplain DaggerType type} and an optional {@linkplain javax.inject.Qualifier qualifier} that
31  * is the lookup key for a binding.
32  */
33 @AutoValue
34 public abstract class Key {
35   /**
36    * A {@link javax.inject.Qualifier} annotation that provides a unique namespace prefix for the
37    * type of this key.
38    */
qualifier()39   public abstract Optional<DaggerAnnotation> qualifier();
40 
41   /** The type represented by this key. */
type()42   public abstract DaggerType type();
43 
44   /**
45    * Distinguishes keys for multibinding contributions that share a {@link #type()} and {@link
46    * #qualifier()}.
47    *
48    * <p>Each multibound map and set has a synthetic multibinding that depends on the specific
49    * contributions to that map or set using keys that identify those multibinding contributions.
50    *
51    * <p>Absent except for multibinding contributions.
52    */
multibindingContributionIdentifier()53   public abstract Optional<MultibindingContributionIdentifier> multibindingContributionIdentifier();
54 
55   /** Returns a {@link Builder} that inherits the properties of this key. */
toBuilder()56   public abstract Builder toBuilder();
57 
58   // The main hashCode/equality bottleneck is in MoreTypes.equivalence(). It's possible that we can
59   // avoid this by tuning that method. Perhaps we can also avoid the issue entirely by interning all
60   // Keys
61   @Memoized
62   @Override
hashCode()63   public abstract int hashCode();
64 
65   @Override
equals(Object o)66   public abstract boolean equals(Object o);
67 
68   @Override
toString()69   public final String toString() {
70     return Joiner.on(' ')
71         .skipNulls()
72         .join(
73             qualifier().map(MoreAnnotationMirrors::toStableString).orElse(null),
74             type(),
75             multibindingContributionIdentifier().orElse(null));
76   }
77 
78   /** Returns a builder for {@link Key}s. */
builder(DaggerType type)79   public static Builder builder(DaggerType type) {
80     return new AutoValue_Key.Builder().type(type);
81   }
82 
83   /** A builder for {@link Key}s. */
84   @CanIgnoreReturnValue
85   @AutoValue.Builder
86   public abstract static class Builder {
type(DaggerType type)87     public abstract Builder type(DaggerType type);
88 
qualifier(Optional<DaggerAnnotation> qualifier)89     public abstract Builder qualifier(Optional<DaggerAnnotation> qualifier);
90 
qualifier(DaggerAnnotation qualifier)91     public abstract Builder qualifier(DaggerAnnotation qualifier);
92 
multibindingContributionIdentifier( Optional<MultibindingContributionIdentifier> identifier)93     public abstract Builder multibindingContributionIdentifier(
94         Optional<MultibindingContributionIdentifier> identifier);
95 
multibindingContributionIdentifier( MultibindingContributionIdentifier identifier)96     public abstract Builder multibindingContributionIdentifier(
97         MultibindingContributionIdentifier identifier);
98 
99     @CheckReturnValue
build()100     public abstract Key build();
101   }
102 
103   /**
104    * An object that identifies a multibinding contribution method and the module class that
105    * contributes it to the graph.
106    *
107    * @see #multibindingContributionIdentifier()
108    */
109   public static final class MultibindingContributionIdentifier {
110     private final String module;
111     private final String bindingElement;
112 
113     /**
114      * @deprecated This is only meant to be called from code in {@code dagger.internal.codegen}.
115      * It is not part of a specified API and may change at any point.
116      */
117     @Deprecated
MultibindingContributionIdentifier( ExecutableElement bindingMethod, TypeElement contributingModule)118     public MultibindingContributionIdentifier(
119         // TODO(ronshapiro): reverse the order of these parameters
120         ExecutableElement bindingMethod, TypeElement contributingModule) {
121       this(
122           bindingMethod.getSimpleName().toString(),
123           contributingModule.getQualifiedName().toString());
124     }
125 
126     // TODO(ronshapiro,dpb): create KeyProxies so that these constructors don't need to be public.
127     @Deprecated
MultibindingContributionIdentifier(String bindingElement, String module)128     public MultibindingContributionIdentifier(String bindingElement, String module) {
129       this.module = module;
130       this.bindingElement = bindingElement;
131     }
132 
133     /**
134      * @deprecated This is only meant to be called from code in {@code dagger.internal.codegen}.
135      * It is not part of a specified API and may change at any point.
136      */
137     @Deprecated
module()138     public String module() {
139       return module;
140     }
141 
142     /**
143      * @deprecated This is only meant to be called from code in {@code dagger.internal.codegen}.
144      * It is not part of a specified API and may change at any point.
145      */
146     @Deprecated
bindingElement()147     public String bindingElement() {
148       return bindingElement;
149     }
150 
151     /**
152      * {@inheritDoc}
153      *
154      * <p>The returned string is human-readable and distinguishes the keys in the same way as the
155      * whole object.
156      */
157     @Override
toString()158     public String toString() {
159       return String.format("%s#%s", module, bindingElement);
160     }
161 
162     @Override
equals(Object obj)163     public boolean equals(Object obj) {
164       if (obj instanceof MultibindingContributionIdentifier) {
165         MultibindingContributionIdentifier other = (MultibindingContributionIdentifier) obj;
166         return module.equals(other.module) && bindingElement.equals(other.bindingElement);
167       }
168       return false;
169     }
170 
171     @Override
hashCode()172     public int hashCode() {
173       return Objects.hash(module, bindingElement);
174     }
175   }
176 }
177