To add to my own questions, I think there are some things I'm just not
understanding about scopes and providers.
Consider the following annotation:
@Target({ TYPE, METHOD })
@Retention(RUNTIME)
@ScopeAnnotation
public @interface AdapterScoped {}
And then a very simple scope:
public class AdapterScope implements Scope {
private Set<Class<?>> classes = new HashSet<Class<?>>();
public <T> Provider<T> scope(Key<T> key, final Provider<T> unscoped)
{
classes.add(key.getTypeLiteral().getRawType());
return new Provider<T>() {
public T get() {
return unscoped.get();
}
};
}
public Set<Class<?>> getClasses() {
return classes;
}
@Override
public String toString() {
return "AdapterScope";
}
}
This is then Guice'd up with:
public class AdapterScopeModule extends AbstractModule {
@Override
protected void configure() {
AdapterScope adapterScope = new AdapterScope();
bindScope(AdapterScoped.class, adapterScope);
bind(AdapterScope.class)
.toInstance(adapterScope);
}
}
I then have a test module that does:
public class SampleModule extends AbstractModule {
@Override
protected void configure() {
bind(SourceToTarget.class)
.in(AdapterScoped.class);
}
}
And a minimal setup:
Injector injector = Guice.createInjector(
new AdapterScopeModule(),
new SampleModule()
);
Now - I see that scope() in the AdapterScope gets called, and it
returns the custom Provider. However, just after that (and before the
Provider inner class is ever called), I get:
com.google.inject.CreationException: Guice creation errors:
com.google.inject.CreationException: Guice creation errors:
1) Could not find a suitable constructor in
org.jadapter.tests.guice.SourceToTarget. Classes must have either one
(and only one) constructor annotated with @Inject or a zero-argument
constructor that is not private.
at org.jadapter.tests.guice.SourceToTarget.class(SourceToTarget.java:
10)
at org.jadapter.tests.guice.SampleModule.configure(SampleModule.java:
12)
1 error
at
com.google.inject.internal.Errors.throwCreationExceptionIfErrorsExist(Errors.java:
416)
at
com.google.inject.internal.InternalInjectorCreator.initializeStatically(InternalInjectorCreator.java:
154)
at
com.google.inject.internal.InternalInjectorCreator.build(InternalInjectorCreator.java:
106)
at com.google.inject.Guice.createInjector(Guice.java:95)
at com.google.inject.Guice.createInjector(Guice.java:72)
at com.google.inject.Guice.createInjector(Guice.java:62)
at
org.jadapter.tests.guice.TestGuiceIntegration.testWiring(TestGuiceIntegration.java:
19)
Now - fair enough - there is no @Inject and no zero-arg constructor
for SourcetoTarget. I had expected to somehow use my own Provider to
instantiate it, in fact. But my Provider inner class is never called.
However, if I create a custom Provider in my configuration and do:
bind(SourceToTarget.class)
.toProvider(SomeRandomProvider)
.in(AdapterScoped.class);
Then SomeRandomProvider.get() is not called until I actually try to
look up an instance for SourceToTarget.class.
Why does Guice try to instantiate SourceToTarget using the default
provider instead of using the provider returned by scope() in my
custom scope (AdapterScope)?
Martin