Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix qualifier issue #338

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,46 @@ public void testNamedFieldInjection_whenUsingQualifierAnnotation() {
.generatesSources(expectedSource);
}

@Test
public void testNamedFieldInjection_whenUsingQualifierAnnotationAsInnerClass() {
JavaFileObject source = JavaFileObjects.forSourceString("test.TestFieldInjection", Joiner.on('\n').join(//
"package test;", //
"import javax.inject.Inject;", //
"import javax.inject.Named;", //
"import javax.inject.Qualifier;", //
"public class TestFieldInjection {", //
" @Inject @Bar Foo foo;", //
" public TestFieldInjection() {}", //
"", //
" @Qualifier", //
" @interface Bar {}", //
"}", //
"class Foo {}"
));

JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestFieldInjection__MemberInjector", Joiner.on('\n').join(//
"package test;", //
"", //
"import java.lang.Override;", //
"import toothpick.MemberInjector;", //
"import toothpick.Scope;", //
"", //
"public final class TestFieldInjection__MemberInjector implements MemberInjector<TestFieldInjection> {", //
" @Override", //
" public void inject(TestFieldInjection target, Scope scope) {", //
" target.foo = scope.getInstance(Foo.class, \"test.TestFieldInjection.Bar\");", //
" }", //
"}" //
));

assert_().about(javaSource())
.that(source)
.processedWith(memberInjectorProcessors())
.compilesWithoutError()
.and()
.generatesSources(expectedSource);
}

@Test
public void testNamedFieldInjection_whenUsingNonQualifierAnnotation() {
JavaFileObject source = JavaFileObjects.forSourceString("test.TestFieldInjection", Joiner.on('\n').join(//
Expand Down
31 changes: 28 additions & 3 deletions toothpick-runtime/src/main/java/toothpick/ScopeImpl.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package toothpick;

import java.lang.annotation.Annotation;
import toothpick.config.Binding;
import toothpick.config.Module;
import toothpick.configuration.ConfigurationHolder;
Expand Down Expand Up @@ -46,7 +47,7 @@ public ScopeImpl(Object name) {

@Override
public <T> T getInstance(Class<T> clazz) {
return getInstance(clazz, null);
return getInstance(clazz, (String) null);
}

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

@Override
public <T> T getInstance(Class<T> clazz, Class<? extends Annotation> name) {
if (name == null) {
return getInstance(clazz, (String) null);
}
return getInstance(clazz, name.getCanonicalName());
}

@Override
public <T> Provider<T> getProvider(Class<T> clazz) {
return getProvider(clazz, null);
return getProvider(clazz, (String) null);
}

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

@Override
public <T> Provider<T> getProvider(Class<T> clazz, Class<? extends Annotation> name) {
if (name == null) {
return getProvider(clazz, (String) null);
}
return getProvider(clazz, name.getCanonicalName());
}

@Override
public <T> Lazy<T> getLazy(Class<T> clazz) {
return getLazy(clazz, null);
return getLazy(clazz, (String) null);
}

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

@Override
public <T> Lazy<T> getLazy(Class<T> clazz, Class<? extends Annotation> name) {
if (name == null) {
return getLazy(clazz, (String) null);
}
return getLazy(clazz, name.getCanonicalName());
}

@Override
public synchronized void installTestModules(Module... modules) {
if (hasTestModules) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,19 @@ public void testNamedInjection_shouldNotBeConfusedWithUnNamedInjection_whenUsing
//WHEN
Foo instance = scope.getInstance(Foo.class, "bar");
Foo instance2 = scope.getInstance(Foo.class, "bar");
Foo instance3 = scope.getInstance(Foo.class, FooName.class.getName());
Foo instance4 = scope.getInstance(Foo.class);
Foo instance3 = scope.getInstance(Foo.class, FooName.class.getCanonicalName());
Foo instance4 = scope.getInstance(Foo.class, FooName.class);
Foo instance5 = scope.getInstance(Foo.class);

//THEN
assertThat(instance, is(namedFooInstance));
assertThat(instance2, is(namedFooInstance));
assertThat(instance3, is(namedFooInstance));
assertThat(instance4, notNullValue());
assertThat(instance4, is(namedFooInstance));
assertThat(instance5, notNullValue());
assertThat(instance, sameInstance(instance2));
assertThat(instance, sameInstance(instance3));
assertThat(instance, not(sameInstance(instance4)));
assertThat(instance, not(sameInstance(instance5)));
}

@Test
Expand All @@ -67,15 +69,17 @@ public void testNamedProviderInjection_shouldNotBeConfusedWithUnNamedInjection()
//WHEN
Provider<Foo> provider = scope.getProvider(Foo.class, "bar");
Provider<Foo> provider2 = scope.getProvider(Foo.class, "bar");
Provider<Foo> provider3 = scope.getProvider(Foo.class, FooName.class.getName());
Provider<Foo> provider4 = scope.getProvider(Foo.class);
Provider<Foo> provider3 = scope.getProvider(Foo.class, FooName.class.getCanonicalName());
Provider<Foo> provider4 = scope.getProvider(Foo.class, FooName.class);
Provider<Foo> provider5 = scope.getProvider(Foo.class);

//THEN
assertThat(provider.get(), is(namedFooInstance));
assertThat(provider2.get(), is(namedFooInstance));
assertThat(provider3.get(), is(namedFooInstance));
assertThat(provider4.get(), notNullValue());
assertThat(provider, not(sameInstance(provider4)));
assertThat(provider4.get(), is(namedFooInstance));
assertThat(provider5.get(), notNullValue());
assertThat(provider, not(sameInstance(provider5)));
}

@Test(expected = IllegalArgumentException.class)
Expand Down
52 changes: 52 additions & 0 deletions toothpick/src/main/java/toothpick/Scope.java
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,22 @@ public interface Scope {
*/
<T> T getInstance(Class<T> clazz, String name);

/**
* Returns the instance of {@code clazz} named {@code name} if one is scoped in the current
* scope, or its ancestors. If there is no such instance, the factory associated
* to the clazz will be used to produce the instance.
* All {@link javax.inject.Inject} annotated fields of the instance are injected after creation.
*
* @param clazz the class for which to obtain an instance in the scope of this scope.
* @param name the name of this instance, if it's null then a unnamed binding is used, otherwise the associated named binding is used.
* Note that the name here is denotated by an annotation class, which must be annotated by {link Qualifier}.
* This is strictly equivalent to use the canonical name of this class as a string.
* @param <T> the type of {@code clazz}.
* @return a scoped instance or a new one produced by the factory associated to {@code clazz}.
* @see toothpick.config.Binding
*/
<T> T getInstance(Class<T> clazz, Class<? extends Annotation> name);

/**
* Requests a provider via an unnamed binding.
*
Expand All @@ -148,6 +164,23 @@ public interface Scope {
*/
<T> Provider<T> getProvider(Class<T> clazz, String name);

/**
* Returns a named {@code Provider} named {@code name} of {@code clazz} if one is scoped in the current
* scope, or its ancestors. If there is no such provider, the factory associated
* to the clazz will be used to create one.
* All {@link javax.inject.Inject} annotated fields of the instance are injected after creation.
*
* @param clazz the class for which to obtain a provider in the scope of this scope.
* @param name the name of this instance, if it's null then a unnamed binding is used, otherwise the associated named binding is used.
* Note that the name here is denotated by an annotation class, which must be annotated by {link Qualifier}.
* This is strictly equivalent to use the canonical name of this class as a string.
* @param <T> the type of {@code clazz}.
* @return a scoped provider or a new one using the factory associated to {@code clazz}.
* Returned providers are thread safe.
* @see toothpick.config.Module
*/
<T> Provider<T> getProvider(Class<T> clazz, Class<? extends Annotation> name);

/**
* Requests a Lazy via an unnamed binding.
*
Expand All @@ -173,6 +206,25 @@ public interface Scope {
*/
<T> Lazy<T> getLazy(Class<T> clazz, String name);

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

/**
* Allows to install modules.
*
Expand Down
2 changes: 1 addition & 1 deletion toothpick/src/main/java/toothpick/config/Binding.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public <A extends Annotation> Binding<T> withName(Class<A> annotationClassWithQu
String.format("Only qualifier annotation annotations can be used to define a binding name. Add @Qualifier to %s",
annotationClassWithQualifierAnnotation));
}
this.name = annotationClassWithQualifierAnnotation.getName();
this.name = annotationClassWithQualifierAnnotation.getCanonicalName();
return this;
}

Expand Down