xref: /aosp_15_r20/external/dagger2/java/dagger/spi/model/Key.java (revision f585d8a307d0621d6060bd7e80091fdcbf94fe27)
1*f585d8a3SJacky Wang /*
2*f585d8a3SJacky Wang  * Copyright (C) 2021 The Dagger Authors.
3*f585d8a3SJacky Wang  *
4*f585d8a3SJacky Wang  * Licensed under the Apache License, Version 2.0 (the "License");
5*f585d8a3SJacky Wang  * you may not use this file except in compliance with the License.
6*f585d8a3SJacky Wang  * You may obtain a copy of the License at
7*f585d8a3SJacky Wang  *
8*f585d8a3SJacky Wang  * http://www.apache.org/licenses/LICENSE-2.0
9*f585d8a3SJacky Wang  *
10*f585d8a3SJacky Wang  * Unless required by applicable law or agreed to in writing, software
11*f585d8a3SJacky Wang  * distributed under the License is distributed on an "AS IS" BASIS,
12*f585d8a3SJacky Wang  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*f585d8a3SJacky Wang  * See the License for the specific language governing permissions and
14*f585d8a3SJacky Wang  * limitations under the License.
15*f585d8a3SJacky Wang  */
16*f585d8a3SJacky Wang 
17*f585d8a3SJacky Wang package dagger.spi.model;
18*f585d8a3SJacky Wang 
19*f585d8a3SJacky Wang 
20*f585d8a3SJacky Wang import com.google.auto.value.AutoValue;
21*f585d8a3SJacky Wang import com.google.auto.value.extension.memoized.Memoized;
22*f585d8a3SJacky Wang import com.google.common.base.Joiner;
23*f585d8a3SJacky Wang import java.util.Optional;
24*f585d8a3SJacky Wang 
25*f585d8a3SJacky Wang /**
26*f585d8a3SJacky Wang  * A {@linkplain DaggerType type} and an optional {@linkplain javax.inject.Qualifier qualifier} that
27*f585d8a3SJacky Wang  * is the lookup key for a binding.
28*f585d8a3SJacky Wang  */
29*f585d8a3SJacky Wang @AutoValue
30*f585d8a3SJacky Wang public abstract class Key {
31*f585d8a3SJacky Wang   /**
32*f585d8a3SJacky Wang    * A {@link javax.inject.Qualifier} annotation that provides a unique namespace prefix for the
33*f585d8a3SJacky Wang    * type of this key.
34*f585d8a3SJacky Wang    */
qualifier()35*f585d8a3SJacky Wang   public abstract Optional<DaggerAnnotation> qualifier();
36*f585d8a3SJacky Wang 
37*f585d8a3SJacky Wang   /** The type represented by this key. */
type()38*f585d8a3SJacky Wang   public abstract DaggerType type();
39*f585d8a3SJacky Wang 
40*f585d8a3SJacky Wang   /**
41*f585d8a3SJacky Wang    * Distinguishes keys for multibinding contributions that share a {@link #type()} and {@link
42*f585d8a3SJacky Wang    * #qualifier()}.
43*f585d8a3SJacky Wang    *
44*f585d8a3SJacky Wang    * <p>Each multibound map and set has a synthetic multibinding that depends on the specific
45*f585d8a3SJacky Wang    * contributions to that map or set using keys that identify those multibinding contributions.
46*f585d8a3SJacky Wang    *
47*f585d8a3SJacky Wang    * <p>Absent except for multibinding contributions.
48*f585d8a3SJacky Wang    */
multibindingContributionIdentifier()49*f585d8a3SJacky Wang   public abstract Optional<MultibindingContributionIdentifier> multibindingContributionIdentifier();
50*f585d8a3SJacky Wang 
51*f585d8a3SJacky Wang   /** Returns a {@link Builder} that inherits the properties of this key. */
toBuilder()52*f585d8a3SJacky Wang   abstract Builder toBuilder();
53*f585d8a3SJacky Wang 
54*f585d8a3SJacky Wang   /** Returns a copy of this key with the type replaced with the given type. */
withType(DaggerType newType)55*f585d8a3SJacky Wang   public Key withType(DaggerType newType) {
56*f585d8a3SJacky Wang     return toBuilder().type(newType).build();
57*f585d8a3SJacky Wang   }
58*f585d8a3SJacky Wang 
59*f585d8a3SJacky Wang   /**
60*f585d8a3SJacky Wang    * Returns a copy of this key with the multibinding contribution identifier replaced with the
61*f585d8a3SJacky Wang    * given multibinding contribution identifier.
62*f585d8a3SJacky Wang    */
withMultibindingContributionIdentifier( DaggerTypeElement contributingModule, DaggerExecutableElement bindingMethod)63*f585d8a3SJacky Wang   public Key withMultibindingContributionIdentifier(
64*f585d8a3SJacky Wang       DaggerTypeElement contributingModule, DaggerExecutableElement bindingMethod) {
65*f585d8a3SJacky Wang     return toBuilder()
66*f585d8a3SJacky Wang         .multibindingContributionIdentifier(contributingModule, bindingMethod)
67*f585d8a3SJacky Wang         .build();
68*f585d8a3SJacky Wang   }
69*f585d8a3SJacky Wang 
70*f585d8a3SJacky Wang   /** Returns a copy of this key with the multibinding contribution identifier, if any, removed. */
withoutMultibindingContributionIdentifier()71*f585d8a3SJacky Wang   public Key withoutMultibindingContributionIdentifier() {
72*f585d8a3SJacky Wang     return toBuilder().multibindingContributionIdentifier(Optional.empty()).build();
73*f585d8a3SJacky Wang   }
74*f585d8a3SJacky Wang 
75*f585d8a3SJacky Wang   // The main hashCode/equality bottleneck is in MoreTypes.equivalence(). It's possible that we can
76*f585d8a3SJacky Wang   // avoid this by tuning that method. Perhaps we can also avoid the issue entirely by interning all
77*f585d8a3SJacky Wang   // Keys
78*f585d8a3SJacky Wang   @Memoized
79*f585d8a3SJacky Wang   @Override
hashCode()80*f585d8a3SJacky Wang   public abstract int hashCode();
81*f585d8a3SJacky Wang 
82*f585d8a3SJacky Wang   @Override
equals(Object o)83*f585d8a3SJacky Wang   public abstract boolean equals(Object o);
84*f585d8a3SJacky Wang 
85*f585d8a3SJacky Wang   @Override
toString()86*f585d8a3SJacky Wang   public final String toString() {
87*f585d8a3SJacky Wang     return Joiner.on(' ')
88*f585d8a3SJacky Wang         .skipNulls()
89*f585d8a3SJacky Wang         .join(
90*f585d8a3SJacky Wang             qualifier().map(DaggerAnnotation::toString).orElse(null),
91*f585d8a3SJacky Wang             type(),
92*f585d8a3SJacky Wang             multibindingContributionIdentifier().orElse(null));
93*f585d8a3SJacky Wang   }
94*f585d8a3SJacky Wang 
95*f585d8a3SJacky Wang   /** Returns a builder for {@link Key}s. */
builder(DaggerType type)96*f585d8a3SJacky Wang   public static Builder builder(DaggerType type) {
97*f585d8a3SJacky Wang     return new AutoValue_Key.Builder().type(type);
98*f585d8a3SJacky Wang   }
99*f585d8a3SJacky Wang 
100*f585d8a3SJacky Wang   /** A builder for {@link Key}s. */
101*f585d8a3SJacky Wang   @AutoValue.Builder
102*f585d8a3SJacky Wang   public abstract static class Builder {
type(DaggerType type)103*f585d8a3SJacky Wang     public abstract Builder type(DaggerType type);
104*f585d8a3SJacky Wang 
qualifier(Optional<DaggerAnnotation> qualifier)105*f585d8a3SJacky Wang     public abstract Builder qualifier(Optional<DaggerAnnotation> qualifier);
106*f585d8a3SJacky Wang 
qualifier(DaggerAnnotation qualifier)107*f585d8a3SJacky Wang     public abstract Builder qualifier(DaggerAnnotation qualifier);
108*f585d8a3SJacky Wang 
multibindingContributionIdentifier( DaggerTypeElement contributingModule, DaggerExecutableElement bindingMethod)109*f585d8a3SJacky Wang     public final Builder multibindingContributionIdentifier(
110*f585d8a3SJacky Wang         DaggerTypeElement contributingModule, DaggerExecutableElement bindingMethod) {
111*f585d8a3SJacky Wang       return multibindingContributionIdentifier(
112*f585d8a3SJacky Wang           Optional.of(
113*f585d8a3SJacky Wang               MultibindingContributionIdentifier.create(contributingModule, bindingMethod)));
114*f585d8a3SJacky Wang     }
115*f585d8a3SJacky Wang 
multibindingContributionIdentifier( Optional<MultibindingContributionIdentifier> identifier)116*f585d8a3SJacky Wang     abstract Builder multibindingContributionIdentifier(
117*f585d8a3SJacky Wang         Optional<MultibindingContributionIdentifier> identifier);
118*f585d8a3SJacky Wang 
build()119*f585d8a3SJacky Wang     public abstract Key build();
120*f585d8a3SJacky Wang   }
121*f585d8a3SJacky Wang 
122*f585d8a3SJacky Wang   /**
123*f585d8a3SJacky Wang    * An object that identifies a multibinding contribution method and the module class that
124*f585d8a3SJacky Wang    * contributes it to the graph.
125*f585d8a3SJacky Wang    *
126*f585d8a3SJacky Wang    * @see #multibindingContributionIdentifier()
127*f585d8a3SJacky Wang    */
128*f585d8a3SJacky Wang   @AutoValue
129*f585d8a3SJacky Wang   public abstract static class MultibindingContributionIdentifier {
create( DaggerTypeElement contributingModule, DaggerExecutableElement bindingMethod)130*f585d8a3SJacky Wang     private static MultibindingContributionIdentifier create(
131*f585d8a3SJacky Wang         DaggerTypeElement contributingModule, DaggerExecutableElement bindingMethod) {
132*f585d8a3SJacky Wang       return new AutoValue_Key_MultibindingContributionIdentifier(
133*f585d8a3SJacky Wang           qualifiedName(contributingModule), simpleName(bindingMethod));
134*f585d8a3SJacky Wang     }
135*f585d8a3SJacky Wang 
136*f585d8a3SJacky Wang     /** Returns the module containing the multibinding method. */
contributingModule()137*f585d8a3SJacky Wang     public abstract String contributingModule();
138*f585d8a3SJacky Wang 
139*f585d8a3SJacky Wang     /** Returns the multibinding method that defines teh multibinding contribution. */
bindingMethod()140*f585d8a3SJacky Wang     public abstract String bindingMethod();
141*f585d8a3SJacky Wang 
142*f585d8a3SJacky Wang     /**
143*f585d8a3SJacky Wang      * {@inheritDoc}
144*f585d8a3SJacky Wang      *
145*f585d8a3SJacky Wang      * <p>The returned string is human-readable and distinguishes the keys in the same way as the
146*f585d8a3SJacky Wang      * whole object.
147*f585d8a3SJacky Wang      */
148*f585d8a3SJacky Wang     @Override
toString()149*f585d8a3SJacky Wang     public final String toString() {
150*f585d8a3SJacky Wang       return String.format("%s#%s", contributingModule(), bindingMethod());
151*f585d8a3SJacky Wang     }
152*f585d8a3SJacky Wang   }
153*f585d8a3SJacky Wang 
qualifiedName(DaggerTypeElement element)154*f585d8a3SJacky Wang   static String qualifiedName(DaggerTypeElement element) {
155*f585d8a3SJacky Wang     switch (element.backend()) {
156*f585d8a3SJacky Wang       case JAVAC:
157*f585d8a3SJacky Wang         return element.javac().getQualifiedName().toString();
158*f585d8a3SJacky Wang       case KSP:
159*f585d8a3SJacky Wang         return element.ksp().getQualifiedName().asString();
160*f585d8a3SJacky Wang     }
161*f585d8a3SJacky Wang     throw new IllegalStateException("Unknown backend: " + element.backend());
162*f585d8a3SJacky Wang   }
163*f585d8a3SJacky Wang 
simpleName(DaggerExecutableElement element)164*f585d8a3SJacky Wang   private static String simpleName(DaggerExecutableElement element) {
165*f585d8a3SJacky Wang     switch (element.backend()) {
166*f585d8a3SJacky Wang       case JAVAC:
167*f585d8a3SJacky Wang         return element.javac().getSimpleName().toString();
168*f585d8a3SJacky Wang       case KSP:
169*f585d8a3SJacky Wang         return element.ksp().getSimpleName().asString();
170*f585d8a3SJacky Wang     }
171*f585d8a3SJacky Wang     throw new IllegalStateException("Unknown backend: " + element.backend());
172*f585d8a3SJacky Wang   }
173*f585d8a3SJacky Wang }
174