SimpleScope help needd

378 views
Skip to first unread message

Richard Maher

unread,
Feb 1, 2011, 11:51:01 PM2/1/11
to google...@googlegroups.com
I have a service that takes a request scope object and a singleton. When I try to run the code below, I get the following error. How do I fix this?

Exception in thread "main" com.google.inject.ProvisionException: Guice provision errors:

1) Error in custom provider, com.google.inject.OutOfScopeException: Cannot access Key[type=com.google.analytics.frontend.feed.impl.gami.GuiceTester$FooImpl, annotation=[none]] outside of a scoping block
  at com.google.analytics.frontend.feed.impl.gami.GuiceTester$FooImpl.class(GuiceTester.java:30)
  while locating com.google.analytics.frontend.feed.impl.gami.GuiceTester$FooImpl
  while locating com.google.analytics.frontend.feed.impl.gami.GuiceTester$Foo
    for field at com.google.analytics.frontend.feed.impl.gami.GuiceTester$DataServiceProvider.foo(GuiceTester.java:1)
  while locating com.google.analytics.frontend.feed.impl.gami.GuiceTester$DataServiceProvider
    for field at com.google.analytics.frontend.feed.impl.gami.GuiceTester$ServiceImpl.unscopedDataServiceProvider(GuiceTester.java:79)
  while locating com.google.analytics.frontend.feed.impl.gami.GuiceTester$ServiceImpl
  while locating com.google.analytics.frontend.feed.impl.gami.GuiceTester$Service

1 error
at com.google.inject.internal.InjectorImpl$4.get(InjectorImpl.java:977)
at com.google.inject.internal.InjectorImpl.getInstance(InjectorImpl.java:1003)
at com.google.analytics.frontend.feed.impl.gami.GuiceTester.main(GuiceTester.java:133)
Caused by: com.google.inject.OutOfScopeException: Cannot access Key[type=com.google.analytics.frontend.feed.impl.gami.GuiceTester$FooImpl, annotation=[none]] outside of a scoping block
at com.google.common.inject.SimpleScope.getScopedObjectMap(SimpleScope.java:110)
at com.google.common.inject.SimpleScope.access$000(SimpleScope.java:48)
at com.google.common.inject.SimpleScope$2.get(SimpleScope.java:94)
at com.google.inject.internal.InternalFactoryToProviderAdapter.get(InternalFactoryToProviderAdapter.java:40)
at com.google.inject.internal.FactoryProxy.get(FactoryProxy.java:54)
at com.google.inject.internal.SingleFieldInjector.inject(SingleFieldInjector.java:53)
at com.google.inject.internal.MembersInjectorImpl.injectMembers(MembersInjectorImpl.java:110)
at com.google.inject.internal.ConstructorInjector.construct(ConstructorInjector.java:94)
at com.google.inject.internal.ConstructorBindingImpl$Factory.get(ConstructorBindingImpl.java:254)
at com.google.inject.internal.SingleFieldInjector.inject(SingleFieldInjector.java:53)
at com.google.inject.internal.MembersInjectorImpl.injectMembers(MembersInjectorImpl.java:110)
at com.google.inject.internal.ConstructorInjector.construct(ConstructorInjector.java:94)
at com.google.inject.internal.ConstructorBindingImpl$Factory.get(ConstructorBindingImpl.java:254)
at com.google.inject.internal.FactoryProxy.get(FactoryProxy.java:54)
at com.google.inject.internal.InjectorImpl$4$1.call(InjectorImpl.java:968)
at com.google.inject.internal.InjectorImpl.callInContext(InjectorImpl.java:1014)
at com.google.inject.internal.InjectorImpl$4.get(InjectorImpl.java:964)
... 2 more

// Code:

public class GuiceTester {
  public interface DataService {

  }

  public interface Foo {
  }

  @RequestScoped
  static class FooImpl implements Foo {
  }

  public interface Bar {
  }

  @Singleton
  static class BarImpl implements Bar {
  }

  static class DataServiceImpl implements DataService {
    private final Foo foo;
    private final Bar bar;

    @Inject
    DataServiceImpl(Foo foo, Bar bar) {
      this.foo = foo;
      this.bar = bar;
    }

    @Override
    public String toString() {
      return "MarsDataService [foo=" + foo + ", bar=" + bar + "]";
    }
  }

  public interface Service {
    Response process(Request request);
  }

  static class Request {
    private final Foo foo;

    Request(Foo foo) {
     this.foo = foo;
    }

    Foo getFoo() {
      return foo;
    }
  }

  static class Response {

  }

  static class ServiceImpl implements  Service {
    @Inject @Named("serviceScope") SimpleScope scope;
    @Inject DataServiceProvider unscopedDataServiceProvider;

    @Override
    public Response process(Request request) {
      scope.enter();
      try {
        // explicitly seed some seed objects...
        scope.seed(Key.get(Foo.class), request.getFoo());
        Provider<DataService> dataServiceProvider =
            scope.scope(Key.get(DataService.class), unscopedDataServiceProvider);
        DataService dataService = dataServiceProvider.get();
        System.out.println("DataService: " + dataService);
      } finally {
        scope.exit();
      }
      return null;
    }
  }

  static class DataServiceProvider implements Provider<DataService> {
    @Inject private Foo foo; // this is request scoped and seeded
    @Inject private Bar bar; // this is a singleton

    @Override
    public DataService get() {
      return new DataServiceImpl(foo, bar);
    }

  }

  public static void main(String[] args) {
    Injector injector =
        Guice.createInjector(Stage.DEVELOPMENT, new AbstractModule() {
          @Override
          protected void configure() {
            bind(Service.class).to(ServiceImpl.class);
            bind(Foo.class).to(FooImpl.class);
            bind(Bar.class).to(BarImpl.class);
            bind(DataServiceProvider.class);

            SimpleScope serviceScope = new SimpleScope();

            // tell Guice about the scope
            bindScope(RequestScoped.class, serviceScope);

            // make our scope instance injectable
            bind(SimpleScope.class)
                .annotatedWith(Names.named("serviceScope"))
                .toInstance(serviceScope);
          }
        });
    Service service = injector.getInstance(Service.class);
    Request request = new Request(new FooImpl());
    service.process(request);
  }
}

// End code

Thanks,

Richard


Fred Faber

unread,
Feb 1, 2011, 11:57:10 PM2/1/11
to google...@googlegroups.com
Simple answer:
  * you bind Foo to FooImpl
  * FooImpl is bound in RequestScope
    - therefore, you can't inject FooImpl (or Foo) outside of Request Scope
  * you inject Foo into DataServiceProvider
  * you inject DataServiceProvider into ServiceImpl
  * you bind Service to ServiceImpl
  * you get an instance of Service outside of Scope

boom!

If you need an instance of Foo in DataServiceProvider, inject Provider<Foo>, and don't call get() until you're in scope.

And traverse upwards as need be...

-Fred

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

Reply all
Reply to author
Forward
0 new messages