Skip to content

Commit 9296709

Browse files
fix qualifier issue
1 parent 54476ca commit 9296709

5 files changed

Lines changed: 133 additions & 12 deletions

File tree

toothpick-compiler/src/test/java/toothpick/compiler/memberinjector/FieldMemberInjectorTest.java

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,46 @@ public void testNamedFieldInjection_whenUsingQualifierAnnotation() {
120120
.generatesSources(expectedSource);
121121
}
122122

123+
@Test
124+
public void testNamedFieldInjection_whenUsingQualifierAnnotationAsInnerClass() {
125+
JavaFileObject source = JavaFileObjects.forSourceString("test.TestFieldInjection", Joiner.on('\n').join(//
126+
"package test;", //
127+
"import javax.inject.Inject;", //
128+
"import javax.inject.Named;", //
129+
"import javax.inject.Qualifier;", //
130+
"public class TestFieldInjection {", //
131+
" @Inject @Bar Foo foo;", //
132+
" public TestFieldInjection() {}", //
133+
"", //
134+
" @Qualifier", //
135+
" @interface Bar {}", //
136+
"}", //
137+
"class Foo {}"
138+
));
139+
140+
JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestFieldInjection__MemberInjector", Joiner.on('\n').join(//
141+
"package test;", //
142+
"", //
143+
"import java.lang.Override;", //
144+
"import toothpick.MemberInjector;", //
145+
"import toothpick.Scope;", //
146+
"", //
147+
"public final class TestFieldInjection__MemberInjector implements MemberInjector<TestFieldInjection> {", //
148+
" @Override", //
149+
" public void inject(TestFieldInjection target, Scope scope) {", //
150+
" target.foo = scope.getInstance(Foo.class, \"test.TestFieldInjection.Bar\");", //
151+
" }", //
152+
"}" //
153+
));
154+
155+
assert_().about(javaSource())
156+
.that(source)
157+
.processedWith(memberInjectorProcessors())
158+
.compilesWithoutError()
159+
.and()
160+
.generatesSources(expectedSource);
161+
}
162+
123163
@Test
124164
public void testNamedFieldInjection_whenUsingNonQualifierAnnotation() {
125165
JavaFileObject source = JavaFileObjects.forSourceString("test.TestFieldInjection", Joiner.on('\n').join(//

toothpick-runtime/src/main/java/toothpick/ScopeImpl.java

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package toothpick;
22

3+
import java.lang.annotation.Annotation;
34
import toothpick.config.Binding;
45
import toothpick.config.Module;
56
import toothpick.configuration.ConfigurationHolder;
@@ -46,7 +47,7 @@ public ScopeImpl(Object name) {
4647

4748
@Override
4849
public <T> T getInstance(Class<T> clazz) {
49-
return getInstance(clazz, null);
50+
return getInstance(clazz, (String) null);
5051
}
5152

5253
@Override
@@ -62,9 +63,17 @@ public <T> T getInstance(Class<T> clazz, String name) {
6263
return t;
6364
}
6465

66+
@Override
67+
public <T> T getInstance(Class<T> clazz, Class<? extends Annotation> name) {
68+
if (name == null) {
69+
return getInstance(clazz, (String) null);
70+
}
71+
return getInstance(clazz, name.getCanonicalName());
72+
}
73+
6574
@Override
6675
public <T> Provider<T> getProvider(Class<T> clazz) {
67-
return getProvider(clazz, null);
76+
return getProvider(clazz, (String) null);
6877
}
6978

7079
@Override
@@ -73,9 +82,17 @@ public <T> Provider<T> getProvider(Class<T> clazz, String name) {
7382
return new ThreadSafeProviderImpl<>(this, clazz, name, false);
7483
}
7584

85+
@Override
86+
public <T> Provider<T> getProvider(Class<T> clazz, Class<? extends Annotation> name) {
87+
if (name == null) {
88+
return getProvider(clazz, (String) null);
89+
}
90+
return getProvider(clazz, name.getCanonicalName());
91+
}
92+
7693
@Override
7794
public <T> Lazy<T> getLazy(Class<T> clazz) {
78-
return getLazy(clazz, null);
95+
return getLazy(clazz, (String) null);
7996
}
8097

8198
@Override
@@ -84,6 +101,14 @@ public <T> Lazy<T> getLazy(Class<T> clazz, String name) {
84101
return new ThreadSafeProviderImpl<>(this, clazz, name, true);
85102
}
86103

104+
@Override
105+
public <T> Lazy<T> getLazy(Class<T> clazz, Class<? extends Annotation> name) {
106+
if (name == null) {
107+
return getLazy(clazz, (String) null);
108+
}
109+
return getLazy(clazz, name.getCanonicalName());
110+
}
111+
87112
@Override
88113
public synchronized void installTestModules(Module... modules) {
89114
if (hasTestModules) {

toothpick-runtime/src/test/java/toothpick/getInstance/NamedInstanceCreation.java

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -45,17 +45,19 @@ public void testNamedInjection_shouldNotBeConfusedWithUnNamedInjection_whenUsing
4545
//WHEN
4646
Foo instance = scope.getInstance(Foo.class, "bar");
4747
Foo instance2 = scope.getInstance(Foo.class, "bar");
48-
Foo instance3 = scope.getInstance(Foo.class, FooName.class.getName());
49-
Foo instance4 = scope.getInstance(Foo.class);
48+
Foo instance3 = scope.getInstance(Foo.class, FooName.class.getCanonicalName());
49+
Foo instance4 = scope.getInstance(Foo.class, FooName.class);
50+
Foo instance5 = scope.getInstance(Foo.class);
5051

5152
//THEN
5253
assertThat(instance, is(namedFooInstance));
5354
assertThat(instance2, is(namedFooInstance));
5455
assertThat(instance3, is(namedFooInstance));
55-
assertThat(instance4, notNullValue());
56+
assertThat(instance4, is(namedFooInstance));
57+
assertThat(instance5, notNullValue());
5658
assertThat(instance, sameInstance(instance2));
5759
assertThat(instance, sameInstance(instance3));
58-
assertThat(instance, not(sameInstance(instance4)));
60+
assertThat(instance, not(sameInstance(instance5)));
5961
}
6062

6163
@Test
@@ -67,15 +69,17 @@ public void testNamedProviderInjection_shouldNotBeConfusedWithUnNamedInjection()
6769
//WHEN
6870
Provider<Foo> provider = scope.getProvider(Foo.class, "bar");
6971
Provider<Foo> provider2 = scope.getProvider(Foo.class, "bar");
70-
Provider<Foo> provider3 = scope.getProvider(Foo.class, FooName.class.getName());
71-
Provider<Foo> provider4 = scope.getProvider(Foo.class);
72+
Provider<Foo> provider3 = scope.getProvider(Foo.class, FooName.class.getCanonicalName());
73+
Provider<Foo> provider4 = scope.getProvider(Foo.class, FooName.class);
74+
Provider<Foo> provider5 = scope.getProvider(Foo.class);
7275

7376
//THEN
7477
assertThat(provider.get(), is(namedFooInstance));
7578
assertThat(provider2.get(), is(namedFooInstance));
7679
assertThat(provider3.get(), is(namedFooInstance));
77-
assertThat(provider4.get(), notNullValue());
78-
assertThat(provider, not(sameInstance(provider4)));
80+
assertThat(provider4.get(), is(namedFooInstance));
81+
assertThat(provider5.get(), notNullValue());
82+
assertThat(provider, not(sameInstance(provider5)));
7983
}
8084

8185
@Test(expected = IllegalArgumentException.class)

toothpick/src/main/java/toothpick/Scope.java

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,22 @@ public interface Scope {
125125
*/
126126
<T> T getInstance(Class<T> clazz, String name);
127127

128+
/**
129+
* Returns the instance of {@code clazz} named {@code name} if one is scoped in the current
130+
* scope, or its ancestors. If there is no such instance, the factory associated
131+
* to the clazz will be used to produce the instance.
132+
* All {@link javax.inject.Inject} annotated fields of the instance are injected after creation.
133+
*
134+
* @param clazz the class for which to obtain an instance in the scope of this scope.
135+
* @param name the name of this instance, if it's null then a unnamed binding is used, otherwise the associated named binding is used.
136+
* Note that the name here is denotated by an annotation class, which must be annotated by {link Qualifier}.
137+
* This is strictly equivalent to use the canonical name of this class as a string.
138+
* @param <T> the type of {@code clazz}.
139+
* @return a scoped instance or a new one produced by the factory associated to {@code clazz}.
140+
* @see toothpick.config.Binding
141+
*/
142+
<T> T getInstance(Class<T> clazz, Class<? extends Annotation> name);
143+
128144
/**
129145
* Requests a provider via an unnamed binding.
130146
*
@@ -148,6 +164,23 @@ public interface Scope {
148164
*/
149165
<T> Provider<T> getProvider(Class<T> clazz, String name);
150166

167+
/**
168+
* Returns a named {@code Provider} named {@code name} of {@code clazz} if one is scoped in the current
169+
* scope, or its ancestors. If there is no such provider, the factory associated
170+
* to the clazz will be used to create one.
171+
* All {@link javax.inject.Inject} annotated fields of the instance are injected after creation.
172+
*
173+
* @param clazz the class for which to obtain a provider in the scope of this scope.
174+
* @param name the name of this instance, if it's null then a unnamed binding is used, otherwise the associated named binding is used.
175+
* Note that the name here is denotated by an annotation class, which must be annotated by {link Qualifier}.
176+
* This is strictly equivalent to use the canonical name of this class as a string.
177+
* @param <T> the type of {@code clazz}.
178+
* @return a scoped provider or a new one using the factory associated to {@code clazz}.
179+
* Returned providers are thread safe.
180+
* @see toothpick.config.Module
181+
*/
182+
<T> Provider<T> getProvider(Class<T> clazz, Class<? extends Annotation> name);
183+
151184
/**
152185
* Requests a Lazy via an unnamed binding.
153186
*
@@ -173,6 +206,25 @@ public interface Scope {
173206
*/
174207
<T> Lazy<T> getLazy(Class<T> clazz, String name);
175208

209+
/**
210+
* Returns a {@code Lazy} named {@code name} of {@code clazz} if one provider is scoped in the current
211+
* scope, or its ancestors. If there is no such provider, the factory associated
212+
* to the clazz will be used to create one.
213+
* All {@link javax.inject.Inject} annotated fields of the instance are injected after creation.
214+
* If the {@code clazz} is annotated with {@link javax.inject.Singleton} then the created provider
215+
* will be scoped in the root scope of the current scope.
216+
*
217+
* @param clazz the class for which to obtain a lazy in the scope of this scope.
218+
* @param name the name of this instance, if it's null then a unnamed binding is used, otherwise the associated named binding is used.
219+
* Note that the name here is denotated by an annotation class, which must be annotated by {link Qualifier}.
220+
* This is strictly equivalent to use the canonical name of this class as a string.
221+
* @param <T> the type of {@code clazz}.
222+
* @return a scoped lazy or a new one using the factory associated to {@code clazz}.
223+
* Returned lazies are thread safe.
224+
* @see toothpick.config.Module
225+
*/
226+
<T> Lazy<T> getLazy(Class<T> clazz, Class<? extends Annotation> name);
227+
176228
/**
177229
* Allows to install modules.
178230
*

toothpick/src/main/java/toothpick/config/Binding.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public <A extends Annotation> Binding<T> withName(Class<A> annotationClassWithQu
3232
String.format("Only qualifier annotation annotations can be used to define a binding name. Add @Qualifier to %s",
3333
annotationClassWithQualifierAnnotation));
3434
}
35-
this.name = annotationClassWithQualifierAnnotation.getName();
35+
this.name = annotationClassWithQualifierAnnotation.getCanonicalName();
3636
return this;
3737
}
3838

0 commit comments

Comments
 (0)