On Jan 23, 4:44 pm, Martin Aspeli <[email protected]> wrote:
> Hi,
>
> I'm trying to integrate Guice with JAdapter (http://code.google.com/p/
> jadapter), at the same time learning Guice in more depth. However, I'm
> getting a little confused. :)
>
> In JAdapter, you write an adapter class like:
>
>   class FooBar implements Foo {
>       public FooBar(Bar context) { ... }
>       public void foo() {}
>   }
>
> The idea is that the single-argument constructor takes the adapted
> context (a Bar) and implemented the interface being adapted to (Foo).
>
> In code using the adapter registry, one might @Inject a
> TransfomerRegistry, and then do:
>
>    Foo foo = transformerRegistry.transform(bar, Foo.class);
>
> The adapter registry looks up the most appropriate adapter from bar to
> a Foo (FooBar.class in this case) and instantiates it.
>
> I'd also like to support @Inject annotations on a FooBar adapter under
> Guice, for example with setters or a void wire() type method, so that
> when the JAdapter registry instantiates a FooBar, it is injected (from
> the default or singleton scope, at least).
>
> My first attempt at this is to define a custom @AdapterScoped scope.
> The idea is that people could do:
>
>     // Register adapters
>     bind(FooBar.class).in(AdapterScoped.class);
>
>     // Register the adapter registry, which can then be injected into
> other classes
>     bind(TransformerRegistry.class).to(GuiceAdapterRegistry.class);
>
> I've managed to write the AdapterScoped annotation, and I've read the
> docs on custom scopes, but I'm still confused. For example, I don't
> understand how/when the SimpleScope is "seeded" (which is not part of
> the Scope interface), or whether there's a way to enumerate types in a
> scope.
>
> More concretely, the two missing pieces for me are:
>
>  - In GuiceAdapterRegistry's constructor, I'd like to iterate over all
> objects in the @AdapterScoped scope, to add them to the internal
> JAdapter registry.
>
>  - In the GuiceAdapterRegistry.transform() implementation, I'd then
> like to instantiate the FooBar class using Guice (or imperatively ask
> Guice to inject the instance just constructed) so that @Inject is
> honoured based on the current Guice configuration. This should also
> allow classes in the @AdapterScoped scope to be injected with unscoped
> instances or instances in the @Singleton scope.
>
> It's possible I'm barking up the wrong tree here, of course. I also
> looked at Multibindings, but since I'm effectively registering classes
> here and want to inject each time a class is instantiated as the
> result of a transform() call, they don't seem to be a match to me.
>
> Any pointers would be greatly appreciated!

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

-- 
You received this message because you are subscribed to the Google Groups 
"google-guice" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/google-guice?hl=en.

Reply via email to