2

Guice users! I have a situation here and I could find a workaround, but I'm not satisfied with my solution. It's very similar to Using the provider from two different scopes, but the answer there doesn't fit my situation.

I have a class like this, which I inject in a lot of places:

MyBusinessClass {
    @Inject
    MyBusinessClass(@AuthenticatedUser User user) {};
}

Up to some moment in the past, I just got the @AuthenticatedUser User from the web session, so I had:

bind(User.class).annotatedWith(AuthenticatedUser.class).toProvider(new AuthenticatedUserProvider());
...
public static class AuthenticatedUserProvider implements Provider<User> {
    @Inject
    Provider<Session> session;
    public User get() {
        return SessionUtil.getUserFromSession(session.get());
    }
}

The problem:

That worked great till I needed to use the same MyBusinessClass inside a different Guice scope (and also outside the request scope). I created a JobScope, very similiar to the scope example in Guice docs, created a kind of JobSession, binded it to the JobScope, and put the @AuthenticatedUser User instance I want injected when MyBusinessClass is used inside the JobSession.

That's where I'm not proud of what I did.. I "improved" my provider to try to provide the @AuthenticatedUser User for all scopes, and I ended up with this ugly provider:

public static class AuthenticatedUserProvider implements Provider<User> {
    @com.google.inject.Inject(optional=true)
    Provider<Session> session;
    @com.google.inject.Inject(optional=true)
    Provider<JobSession> jobSession;
    @Override
    public User get() {
        try {
            return SessionUtil.getUserFromSession(session.get());
        } catch (Exception e) {
            try {
                return SessionUtil.getUserFromJobSession(jobSession.get());
            } catch (Exception ee) {
                throw new IllegalStateException("Current scope doesn't have a auth user!");
            }
        }
    }
}

The provider does a try-an-error approach to find which session (web session or job session) is available and return the user for the first one it is able to get. It works because of the @com.google.inject.Inject(optional=true) and also because the scopes are mutually exclusive.

Is there a better way to achieve this? I just want to have MyBusinessClass injected with @AuthenticatedUser User for any scope it is used transparently, and let Guice modules/providers find the right place to get the satisfying instance.

Community
  • 1
  • 1
Bruno Medeiros
  • 2,251
  • 21
  • 34
  • I don't think the `optional=true` is necessary – Tavian Barnes Dec 16 '14 at 19:36
  • Did you try `ServletScopes.scopeRequest()`? – Tavian Barnes Dec 16 '14 at 19:37
  • `optional=true` is necessary because inject the provider when the object is out of scope gives me an error. I didn't know about `ServletScopes.scopeRequest()`, but it unfortunately doesn't help here, because my JobScope is more complex than call a `Callable` :( – Bruno Medeiros Dec 17 '14 at 20:15
  • Injecting `Provider`s is supposed to work even if the object is out of scope. It's only when you call `.get()` that you'll get `OutOfScopeException`. – Tavian Barnes Dec 17 '14 at 20:19
  • Tavian, that's my problem.. SInce I don't have a way to check in which scopes I'm currently in, I have no way to choose which provider I should call the `get()`.. The only way is to call each of them until there is no error. – Bruno Medeiros Apr 13 '15 at 17:42
  • You can use this trick to see if you're inside a web request: http://stackoverflow.com/a/17411033/502399 – Tavian Barnes May 25 '15 at 14:01
  • That would be control scopes by hand.. I guess it would work, but it's as ugly as what I have today :( – Bruno Medeiros Jun 03 '15 at 18:06

0 Answers0