xref: /aosp_15_r20/external/dagger2/javatests/dagger/internal/codegen/BindsMethodValidationTest.java (revision f585d8a307d0621d6060bd7e80091fdcbf94fe27)
1*f585d8a3SJacky Wang /*
2*f585d8a3SJacky Wang  * Copyright (C) 2016 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.internal.codegen;
18*f585d8a3SJacky Wang 
19*f585d8a3SJacky Wang import static dagger.internal.codegen.DaggerModuleMethodSubject.Factory.assertThatMethodInUnannotatedClass;
20*f585d8a3SJacky Wang import static dagger.internal.codegen.DaggerModuleMethodSubject.Factory.assertThatModuleMethod;
21*f585d8a3SJacky Wang import static java.lang.annotation.RetentionPolicy.RUNTIME;
22*f585d8a3SJacky Wang 
23*f585d8a3SJacky Wang import androidx.room.compiler.processing.XProcessingEnv;
24*f585d8a3SJacky Wang import androidx.room.compiler.processing.util.Source;
25*f585d8a3SJacky Wang import com.google.common.collect.ImmutableList;
26*f585d8a3SJacky Wang import dagger.Module;
27*f585d8a3SJacky Wang import dagger.multibindings.IntKey;
28*f585d8a3SJacky Wang import dagger.multibindings.LongKey;
29*f585d8a3SJacky Wang import dagger.producers.ProducerModule;
30*f585d8a3SJacky Wang import dagger.testing.compile.CompilerTests;
31*f585d8a3SJacky Wang import java.lang.annotation.Annotation;
32*f585d8a3SJacky Wang import java.lang.annotation.Retention;
33*f585d8a3SJacky Wang import java.util.Collection;
34*f585d8a3SJacky Wang import javax.inject.Qualifier;
35*f585d8a3SJacky Wang import org.junit.Test;
36*f585d8a3SJacky Wang import org.junit.runner.RunWith;
37*f585d8a3SJacky Wang import org.junit.runners.Parameterized;
38*f585d8a3SJacky Wang import org.junit.runners.Parameterized.Parameters;
39*f585d8a3SJacky Wang 
40*f585d8a3SJacky Wang @RunWith(Parameterized.class)
41*f585d8a3SJacky Wang public class BindsMethodValidationTest {
42*f585d8a3SJacky Wang   @Parameters
data()43*f585d8a3SJacky Wang   public static Collection<Object[]> data() {
44*f585d8a3SJacky Wang     return ImmutableList.copyOf(new Object[][] {{Module.class}, {ProducerModule.class}});
45*f585d8a3SJacky Wang   }
46*f585d8a3SJacky Wang 
47*f585d8a3SJacky Wang   private final String moduleAnnotation;
48*f585d8a3SJacky Wang   private final String moduleDeclaration;
49*f585d8a3SJacky Wang 
BindsMethodValidationTest(Class<? extends Annotation> moduleAnnotation)50*f585d8a3SJacky Wang   public BindsMethodValidationTest(Class<? extends Annotation> moduleAnnotation) {
51*f585d8a3SJacky Wang     this.moduleAnnotation = "@" + moduleAnnotation.getCanonicalName();
52*f585d8a3SJacky Wang     moduleDeclaration = this.moduleAnnotation + " abstract class %s { %s }";
53*f585d8a3SJacky Wang   }
54*f585d8a3SJacky Wang 
55*f585d8a3SJacky Wang   @Test
noExtensionForBinds()56*f585d8a3SJacky Wang   public void noExtensionForBinds() {
57*f585d8a3SJacky Wang     Source module =
58*f585d8a3SJacky Wang         CompilerTests.kotlinSource(
59*f585d8a3SJacky Wang             "test.TestModule.kt",
60*f585d8a3SJacky Wang             "package test",
61*f585d8a3SJacky Wang             "",
62*f585d8a3SJacky Wang             "import dagger.Binds",
63*f585d8a3SJacky Wang             "",
64*f585d8a3SJacky Wang             moduleAnnotation,
65*f585d8a3SJacky Wang             "interface TestModule {",
66*f585d8a3SJacky Wang             "  @Binds fun FooImpl.bindObject(): Foo",
67*f585d8a3SJacky Wang             "}");
68*f585d8a3SJacky Wang     Source foo =
69*f585d8a3SJacky Wang         CompilerTests.javaSource(
70*f585d8a3SJacky Wang             "test.Foo", // Prevents formatting onto a single line
71*f585d8a3SJacky Wang             "package test;",
72*f585d8a3SJacky Wang             "",
73*f585d8a3SJacky Wang             "interface Foo {}");
74*f585d8a3SJacky Wang     Source fooImpl =
75*f585d8a3SJacky Wang         CompilerTests.javaSource(
76*f585d8a3SJacky Wang             "test.FooImpl", // Prevents formatting onto a single line
77*f585d8a3SJacky Wang             "package test;",
78*f585d8a3SJacky Wang             "",
79*f585d8a3SJacky Wang             "class FooImpl implements Foo {",
80*f585d8a3SJacky Wang             "   @Inject FooImpl() {}",
81*f585d8a3SJacky Wang             "}");
82*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(module, foo, fooImpl)
83*f585d8a3SJacky Wang         .compile(
84*f585d8a3SJacky Wang             subject -> {
85*f585d8a3SJacky Wang               subject.hasErrorCount(1);
86*f585d8a3SJacky Wang               subject.hasErrorContaining("@Binds methods can not be an extension function");
87*f585d8a3SJacky Wang             });
88*f585d8a3SJacky Wang   }
89*f585d8a3SJacky Wang 
90*f585d8a3SJacky Wang   @Test
noExtensionForProvides()91*f585d8a3SJacky Wang   public void noExtensionForProvides() {
92*f585d8a3SJacky Wang     Source module =
93*f585d8a3SJacky Wang         CompilerTests.kotlinSource(
94*f585d8a3SJacky Wang             "test.TestModule.kt",
95*f585d8a3SJacky Wang             "package test",
96*f585d8a3SJacky Wang             "",
97*f585d8a3SJacky Wang             "import dagger.Provides",
98*f585d8a3SJacky Wang             "",
99*f585d8a3SJacky Wang             moduleAnnotation,
100*f585d8a3SJacky Wang             "object TestModule {",
101*f585d8a3SJacky Wang             "  @Provides fun Foo.providesString(): String = \"hello\"",
102*f585d8a3SJacky Wang             "}");
103*f585d8a3SJacky Wang     Source foo =
104*f585d8a3SJacky Wang         CompilerTests.javaSource(
105*f585d8a3SJacky Wang             "test.Foo", // Prevents formatting onto a single line
106*f585d8a3SJacky Wang             "package test;",
107*f585d8a3SJacky Wang             "",
108*f585d8a3SJacky Wang             "class Foo {",
109*f585d8a3SJacky Wang             "  @Inject Foo() {}",
110*f585d8a3SJacky Wang             "}");
111*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(module, foo)
112*f585d8a3SJacky Wang         .compile(
113*f585d8a3SJacky Wang             subject -> {
114*f585d8a3SJacky Wang               subject.hasErrorCount(1);
115*f585d8a3SJacky Wang               subject.hasErrorContaining("@Provides methods can not be an extension function");
116*f585d8a3SJacky Wang             });
117*f585d8a3SJacky Wang   }
118*f585d8a3SJacky Wang 
119*f585d8a3SJacky Wang   @Test
nonAbstract()120*f585d8a3SJacky Wang   public void nonAbstract() {
121*f585d8a3SJacky Wang     assertThatMethod("@Binds Object concrete(String impl) { return null; }")
122*f585d8a3SJacky Wang         .hasError("must be abstract");
123*f585d8a3SJacky Wang   }
124*f585d8a3SJacky Wang 
125*f585d8a3SJacky Wang   @Test
notAssignable()126*f585d8a3SJacky Wang   public void notAssignable() {
127*f585d8a3SJacky Wang     assertThatMethod("@Binds abstract String notAssignable(Object impl);").hasError("assignable");
128*f585d8a3SJacky Wang   }
129*f585d8a3SJacky Wang 
130*f585d8a3SJacky Wang   @Test
moreThanOneParameter()131*f585d8a3SJacky Wang   public void moreThanOneParameter() {
132*f585d8a3SJacky Wang     assertThatMethod("@Binds abstract Object tooManyParameters(String s1, String s2);")
133*f585d8a3SJacky Wang         .hasError("one parameter");
134*f585d8a3SJacky Wang   }
135*f585d8a3SJacky Wang 
136*f585d8a3SJacky Wang   @Test
typeParameters()137*f585d8a3SJacky Wang   public void typeParameters() {
138*f585d8a3SJacky Wang     assertThatMethod("@Binds abstract <S, T extends S> S generic(T t);")
139*f585d8a3SJacky Wang         .hasError("type parameters");
140*f585d8a3SJacky Wang   }
141*f585d8a3SJacky Wang 
142*f585d8a3SJacky Wang   @Test
notInModule()143*f585d8a3SJacky Wang   public void notInModule() {
144*f585d8a3SJacky Wang     assertThatMethodInUnannotatedClass("@Binds abstract Object bindObject(String s);")
145*f585d8a3SJacky Wang         .hasError("within a @Module or @ProducerModule");
146*f585d8a3SJacky Wang   }
147*f585d8a3SJacky Wang 
148*f585d8a3SJacky Wang   @Test
throwsException()149*f585d8a3SJacky Wang   public void throwsException() {
150*f585d8a3SJacky Wang     assertThatMethod("@Binds abstract Object throwsException(String s1) throws RuntimeException;")
151*f585d8a3SJacky Wang         .hasError("may not throw");
152*f585d8a3SJacky Wang   }
153*f585d8a3SJacky Wang 
154*f585d8a3SJacky Wang   @Test
returnsVoid()155*f585d8a3SJacky Wang   public void returnsVoid() {
156*f585d8a3SJacky Wang     assertThatMethod("@Binds abstract void returnsVoid(Object impl);").hasError("void");
157*f585d8a3SJacky Wang   }
158*f585d8a3SJacky Wang 
159*f585d8a3SJacky Wang   @Test
tooManyQualifiersOnMethod()160*f585d8a3SJacky Wang   public void tooManyQualifiersOnMethod() {
161*f585d8a3SJacky Wang     assertThatMethod(
162*f585d8a3SJacky Wang             "@Binds @Qualifier1 @Qualifier2 abstract String tooManyQualifiers(String impl);")
163*f585d8a3SJacky Wang         .importing(Qualifier1.class, Qualifier2.class)
164*f585d8a3SJacky Wang         .hasError("more than one @Qualifier");
165*f585d8a3SJacky Wang   }
166*f585d8a3SJacky Wang 
167*f585d8a3SJacky Wang   @Test
tooManyQualifiersOnParameter()168*f585d8a3SJacky Wang   public void tooManyQualifiersOnParameter() {
169*f585d8a3SJacky Wang     assertThatMethod(
170*f585d8a3SJacky Wang             "@Binds abstract String tooManyQualifiers(@Qualifier1 @Qualifier2 String impl);")
171*f585d8a3SJacky Wang         .importing(Qualifier1.class, Qualifier2.class)
172*f585d8a3SJacky Wang         .hasError("more than one @Qualifier");
173*f585d8a3SJacky Wang   }
174*f585d8a3SJacky Wang 
175*f585d8a3SJacky Wang   @Test
noParameters()176*f585d8a3SJacky Wang   public void noParameters() {
177*f585d8a3SJacky Wang     assertThatMethod("@Binds abstract Object noParameters();").hasError("one parameter");
178*f585d8a3SJacky Wang   }
179*f585d8a3SJacky Wang 
180*f585d8a3SJacky Wang   @Test
setElementsNotAssignable()181*f585d8a3SJacky Wang   public void setElementsNotAssignable() {
182*f585d8a3SJacky Wang     assertThatMethod(
183*f585d8a3SJacky Wang             "@Binds @ElementsIntoSet abstract Set<String> bindSetOfIntegers(Set<Integer> ints);")
184*f585d8a3SJacky Wang         .hasError("assignable");
185*f585d8a3SJacky Wang   }
186*f585d8a3SJacky Wang 
187*f585d8a3SJacky Wang   @Test
setElements_primitiveArgument()188*f585d8a3SJacky Wang   public void setElements_primitiveArgument() {
189*f585d8a3SJacky Wang     assertThatMethod("@Binds @ElementsIntoSet abstract Set<Number> bindInt(int integer);")
190*f585d8a3SJacky Wang         .hasError("assignable");
191*f585d8a3SJacky Wang   }
192*f585d8a3SJacky Wang 
193*f585d8a3SJacky Wang   @Test
elementsIntoSet_withRawSets()194*f585d8a3SJacky Wang   public void elementsIntoSet_withRawSets() {
195*f585d8a3SJacky Wang     assertThatMethod("@Binds @ElementsIntoSet abstract Set bindRawSet(HashSet hashSet);")
196*f585d8a3SJacky Wang         .hasError("cannot return a raw Set");
197*f585d8a3SJacky Wang   }
198*f585d8a3SJacky Wang 
199*f585d8a3SJacky Wang   @Test
intoMap_noMapKey()200*f585d8a3SJacky Wang   public void intoMap_noMapKey() {
201*f585d8a3SJacky Wang     assertThatMethod("@Binds @IntoMap abstract Object bindNoMapKey(String string);")
202*f585d8a3SJacky Wang         .hasError("methods of type map must declare a map key");
203*f585d8a3SJacky Wang   }
204*f585d8a3SJacky Wang 
205*f585d8a3SJacky Wang   @Test
intoMap_multipleMapKeys()206*f585d8a3SJacky Wang   public void intoMap_multipleMapKeys() {
207*f585d8a3SJacky Wang     assertThatMethod(
208*f585d8a3SJacky Wang             "@Binds @IntoMap @IntKey(1) @LongKey(2L) abstract Object manyMapKeys(String string);")
209*f585d8a3SJacky Wang         .importing(IntKey.class, LongKey.class)
210*f585d8a3SJacky Wang         .hasError("may not have more than one map key");
211*f585d8a3SJacky Wang   }
212*f585d8a3SJacky Wang 
213*f585d8a3SJacky Wang   @Test
bindsMissingTypeInParameterHierarchy()214*f585d8a3SJacky Wang   public void bindsMissingTypeInParameterHierarchy() {
215*f585d8a3SJacky Wang     Source module =
216*f585d8a3SJacky Wang         CompilerTests.javaSource(
217*f585d8a3SJacky Wang             "test.TestComponent",
218*f585d8a3SJacky Wang             "package test;",
219*f585d8a3SJacky Wang             "",
220*f585d8a3SJacky Wang             "import dagger.Binds;",
221*f585d8a3SJacky Wang             "",
222*f585d8a3SJacky Wang             moduleAnnotation,
223*f585d8a3SJacky Wang             "interface TestModule {",
224*f585d8a3SJacky Wang             "  @Binds String bindObject(Child<String> child);",
225*f585d8a3SJacky Wang             "}");
226*f585d8a3SJacky Wang 
227*f585d8a3SJacky Wang     Source child =
228*f585d8a3SJacky Wang         CompilerTests.javaSource(
229*f585d8a3SJacky Wang             "test.Child",
230*f585d8a3SJacky Wang             "package test;",
231*f585d8a3SJacky Wang             "",
232*f585d8a3SJacky Wang             "class Child<T> extends Parent<T> {}");
233*f585d8a3SJacky Wang 
234*f585d8a3SJacky Wang     Source parent =
235*f585d8a3SJacky Wang         CompilerTests.javaSource(
236*f585d8a3SJacky Wang             "test.Parent",
237*f585d8a3SJacky Wang             "package test;",
238*f585d8a3SJacky Wang             "",
239*f585d8a3SJacky Wang             "class Parent<T> extends MissingType {}");
240*f585d8a3SJacky Wang 
241*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(module, child, parent)
242*f585d8a3SJacky Wang         .compile(
243*f585d8a3SJacky Wang             subject -> {
244*f585d8a3SJacky Wang               switch (CompilerTests.backend(subject)) {
245*f585d8a3SJacky Wang                 case JAVAC:
246*f585d8a3SJacky Wang                   subject.hasErrorCount(3);
247*f585d8a3SJacky Wang                   subject.hasErrorContaining(
248*f585d8a3SJacky Wang                       "cannot find symbol"
249*f585d8a3SJacky Wang                           + "\n  symbol: class MissingType");
250*f585d8a3SJacky Wang                   break;
251*f585d8a3SJacky Wang                 case KSP:
252*f585d8a3SJacky Wang                   subject.hasErrorCount(2);
253*f585d8a3SJacky Wang                   break;
254*f585d8a3SJacky Wang               }
255*f585d8a3SJacky Wang               // TODO(b/248552462): Javac and KSP should match once this bug is fixed.
256*f585d8a3SJacky Wang               boolean isJavac = CompilerTests.backend(subject) == XProcessingEnv.Backend.JAVAC;
257*f585d8a3SJacky Wang               subject.hasErrorContaining(
258*f585d8a3SJacky Wang                   String.format(
259*f585d8a3SJacky Wang                       "ModuleProcessingStep was unable to process 'test.TestModule' because '%s' "
260*f585d8a3SJacky Wang                           + "could not be resolved.",
261*f585d8a3SJacky Wang                       isJavac ? "MissingType" : "error.NonExistentClass"));
262*f585d8a3SJacky Wang               subject.hasErrorContaining(
263*f585d8a3SJacky Wang                   String.format(
264*f585d8a3SJacky Wang                       "BindingMethodProcessingStep was unable to process"
265*f585d8a3SJacky Wang                           + " 'bindObject(test.Child<java.lang.String>)' because '%1$s' could not "
266*f585d8a3SJacky Wang                           + "be resolved."
267*f585d8a3SJacky Wang                           + "\n  "
268*f585d8a3SJacky Wang                           + "\n  Dependency trace:"
269*f585d8a3SJacky Wang                           + "\n      => element (INTERFACE): test.TestModule"
270*f585d8a3SJacky Wang                           + "\n      => element (METHOD): bindObject(test.Child<java.lang.String>)"
271*f585d8a3SJacky Wang                           + "\n      => element (PARAMETER): child"
272*f585d8a3SJacky Wang                           + "\n      => type (DECLARED parameter): test.Child<java.lang.String>"
273*f585d8a3SJacky Wang                           + "\n      => type (DECLARED supertype): test.Parent<java.lang.String>"
274*f585d8a3SJacky Wang                           + "\n      => type (ERROR supertype): %1$s",
275*f585d8a3SJacky Wang                       isJavac ? "MissingType" : "error.NonExistentClass"));
276*f585d8a3SJacky Wang             });
277*f585d8a3SJacky Wang   }
278*f585d8a3SJacky Wang 
279*f585d8a3SJacky Wang 
280*f585d8a3SJacky Wang   @Test
bindsMissingTypeInReturnTypeHierarchy()281*f585d8a3SJacky Wang   public void bindsMissingTypeInReturnTypeHierarchy() {
282*f585d8a3SJacky Wang     Source module =
283*f585d8a3SJacky Wang         CompilerTests.javaSource(
284*f585d8a3SJacky Wang             "test.TestComponent",
285*f585d8a3SJacky Wang             "package test;",
286*f585d8a3SJacky Wang             "",
287*f585d8a3SJacky Wang             "import dagger.Binds;",
288*f585d8a3SJacky Wang             "",
289*f585d8a3SJacky Wang             moduleAnnotation,
290*f585d8a3SJacky Wang             "interface TestModule {",
291*f585d8a3SJacky Wang             "  @Binds Child<String> bindChild(String str);",
292*f585d8a3SJacky Wang             "}");
293*f585d8a3SJacky Wang 
294*f585d8a3SJacky Wang     Source child =
295*f585d8a3SJacky Wang         CompilerTests.javaSource(
296*f585d8a3SJacky Wang             "test.Child",
297*f585d8a3SJacky Wang             "package test;",
298*f585d8a3SJacky Wang             "",
299*f585d8a3SJacky Wang             "class Child<T> extends Parent<T> {}");
300*f585d8a3SJacky Wang 
301*f585d8a3SJacky Wang     Source parent =
302*f585d8a3SJacky Wang         CompilerTests.javaSource(
303*f585d8a3SJacky Wang             "test.Parent",
304*f585d8a3SJacky Wang             "package test;",
305*f585d8a3SJacky Wang             "",
306*f585d8a3SJacky Wang             "class Parent<T> extends MissingType {}");
307*f585d8a3SJacky Wang 
308*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(module, child, parent)
309*f585d8a3SJacky Wang         .compile(
310*f585d8a3SJacky Wang             subject -> {
311*f585d8a3SJacky Wang               switch (CompilerTests.backend(subject)) {
312*f585d8a3SJacky Wang                 case JAVAC:
313*f585d8a3SJacky Wang                   subject.hasErrorCount(3);
314*f585d8a3SJacky Wang                   subject.hasErrorContaining(
315*f585d8a3SJacky Wang                       "cannot find symbol"
316*f585d8a3SJacky Wang                           + "\n  symbol: class MissingType");
317*f585d8a3SJacky Wang                   break;
318*f585d8a3SJacky Wang                 case KSP:
319*f585d8a3SJacky Wang                   subject.hasErrorCount(2);
320*f585d8a3SJacky Wang                   break;
321*f585d8a3SJacky Wang               }
322*f585d8a3SJacky Wang               // TODO(b/248552462): Javac and KSP should match once this bug is fixed.
323*f585d8a3SJacky Wang               boolean isJavac = CompilerTests.backend(subject) == XProcessingEnv.Backend.JAVAC;
324*f585d8a3SJacky Wang               subject.hasErrorContaining(
325*f585d8a3SJacky Wang                   String.format(
326*f585d8a3SJacky Wang                       "ModuleProcessingStep was unable to process 'test.TestModule' because '%s' "
327*f585d8a3SJacky Wang                           + "could not be resolved.",
328*f585d8a3SJacky Wang                       isJavac ? "MissingType" : "error.NonExistentClass"));
329*f585d8a3SJacky Wang               subject.hasErrorContaining(
330*f585d8a3SJacky Wang                   String.format(
331*f585d8a3SJacky Wang                       "BindingMethodProcessingStep was unable to process "
332*f585d8a3SJacky Wang                           + "'bindChild(java.lang.String)' because '%1$s' could not be"
333*f585d8a3SJacky Wang                           + " resolved."
334*f585d8a3SJacky Wang                           + "\n  "
335*f585d8a3SJacky Wang                           + "\n  Dependency trace:"
336*f585d8a3SJacky Wang                           + "\n      => element (INTERFACE): test.TestModule"
337*f585d8a3SJacky Wang                           + "\n      => element (METHOD): bindChild(java.lang.String)"
338*f585d8a3SJacky Wang                           + "\n      => type (DECLARED return type): test.Child<java.lang.String>"
339*f585d8a3SJacky Wang                           + "\n      => type (DECLARED supertype): test.Parent<java.lang.String>"
340*f585d8a3SJacky Wang                           + "\n      => type (ERROR supertype): %1$s",
341*f585d8a3SJacky Wang                       isJavac ? "MissingType" : "error.NonExistentClass"));
342*f585d8a3SJacky Wang             });
343*f585d8a3SJacky Wang   }
344*f585d8a3SJacky Wang 
assertThatMethod(String method)345*f585d8a3SJacky Wang   private DaggerModuleMethodSubject assertThatMethod(String method) {
346*f585d8a3SJacky Wang     return assertThatModuleMethod(method).withDeclaration(moduleDeclaration);
347*f585d8a3SJacky Wang   }
348*f585d8a3SJacky Wang 
349*f585d8a3SJacky Wang   @Qualifier
350*f585d8a3SJacky Wang   @Retention(RUNTIME)
351*f585d8a3SJacky Wang   public @interface Qualifier1 {}
352*f585d8a3SJacky Wang 
353*f585d8a3SJacky Wang   @Qualifier
354*f585d8a3SJacky Wang   @Retention(RUNTIME)
355*f585d8a3SJacky Wang   public @interface Qualifier2 {}
356*f585d8a3SJacky Wang }
357